Guten Mittag meine Freunde, ich habe ein Problem: Ich habe mir selbstverständlich alle gegebenen Anleitungen durchgelesen, leider ist mir das mit dem Timer/Interrupt nicht ganz klar geworden. ich habe 2 LEDS an meinen AtMega 8 angeschlossen (LED1 =^ PD6; LED2 =^ PD5) sowie einen Taster (taster =^ PD2), nun mein Projekt: Ich möchte, dass eine LED (PD6) leuchtet, sobald ich den Taster betätigt habe. Damit beginnt auch der Timer zu laufen, der nach einpaar Stunden (sagen wir 2) die andere LED (PD5) zum Leuchten bringt. Dann wieder 2 Stunden Pause, und die LED (PD5)soll wieder blinken. Währenddessen soll die LED1 ununterbrochen die ganze Zeit leuchten. Wie würdet ihr das in C schreiben? Ich bin damit leicht überfordert. Ich bin erfreut über Tipps. Vielen Dank
:
Verschoben durch User
moin versuch mal rauszubekommen, wie lange du mit einem 16bit Timer bei gegebener Taktfreq. des MC, etwas verzögern kannst . Stichwort:Vorteiler mfg
ja, also... wie findet man das heraus? Ich weiß nicht, inwiefern Overflows, etc.. Zeitangaben sind.
kopfkratz Also wenn Du das Datenblatt nicht verstehst und dann noch die Tutorials hier samt FAQ Timer von Karl-Heinz, dann solltest Du Dich entweder nach einem anderen Hobby umsehen oder Deine Hausaufgabe mit dem Lehrer besprechen :-P Was Du brauchst: 1. Tastenentprellung (PeDa hilft da weiter) 2. Variable die den Tastendruck speichert 3. Timer der Dir die aktuelle Zeit in einer volatile Variable angibt 4. Hauptprogramm das beide Variablen entsprechend auswertet Und nun ran an den Speck, egal ob in Assembler, BASIC, C, PASCAL oder ZZZZZZZ :-P
kopfkratzer schrieb: > 2. Variable die den Tastendruck speichert Okay, wieso muss der Tastendruck als solcher gespeichert werden? Ich drücke den Taster, eine LED fängt an zu leuchten und der Timer geht los. Ab da ist der Taster ja völlig uninteressant, da er nur einmal (zu Anfang) betätigt wird/wurde. > Vorteiler Könntest du mir ne Beispielrechnung geben, wie ich die Maximaldauer errechnen kann? Danke
Oldie schrieb: > kopfkratzer schrieb: >> 2. Variable die den Tastendruck speichert > > Okay, wieso muss der Tastendruck als solcher gespeichert werden? > Ich drücke den Taster, eine LED fängt an zu leuchten und der Timer geht > los. Ab da ist der Taster ja völlig uninteressant, da er nur einmal (zu > Anfang) betätigt wird/wurde. > ROFLMAO Gut dann ist es noch schlimmer als befürchtet. Woher willst Du denn wissen das der Taster gedrückt wurde ? Was soll denn passieren wenn während der 2 Stunden der Taster nochmal gedrückt wird, wieder von vorne anfangen ? Und jetzt erkläre mir mal bitte wie Du aus den beiden Timestamps die zwei Stunden errechnen willst ? Achja woher kommen die Timestamps ? Besser nochmal beim Lehrer nachfragen ;-)
Oldie schrieb: > Ich drücke den Taster Das denkst du, inwirklichkeit drückst du ihn mehrfach - ganz einfach weil er prellt. Falls du über ein Speicher-Scope verfügst, kannst du den elektrischen Part eines Tasterdrucks respektive Schalterbetätigung mal ansehen. Du wirst dich wundern. > Könntest du mir ne Beispielrechnung geben, wie ich die Maximaldauer > errechnen kann? Man zählt mithilfe eines Timer eine Variable hoch und leitet davon die tatsächlich gewünchte Zeit ab.
Oldie schrieb: > Okay, wieso muss der Tastendruck als solcher gespeichert werden? > Ich drücke den Taster, eine LED fängt an zu leuchten und der Timer geht > los. Oldie schrieb: > sowie einen Taster (taster =^ PD2), nun mein Projekt: > Ich möchte, dass eine LED (PD6) leuchtet, sobald ich den Taster betätigt > habe. Damit beginnt auch der Timer zu laufen, der nach einpaar Stunden > (sagen wir 2) die andere LED (PD5) zum Leuchten bringt. Dann wieder 2 > Stunden Pause, und die LED (PD5)soll wieder blinken. Währenddessen soll > die LED1 {=PD6} ununterbrochen die ganze Zeit leuchten. Grundzustand : Keine Taste gedrück, keine LED leuchtet (wahrscheinlich ist das der Zustand nach dem Einschalten deines Controllers) dann wird irgendwann die Taste gedrückt, Den Zustand "Taste ist (verlässlich)gedrückt" bekommst du als Ergebniss deiner Entprell-Routine. Das Betä#tigen der Taste führt zum sofortigen und immerwährenden Leuchten von LED1, sowie zum "normalen Lampen-Geleuchte", welche folgendes macht: - abwarten, bis eine Zeit t1 abgelaufen ist - am Ende der Zeit t1 die LED 2 statisch einschalten (so lese ich das raus aus deinem post) Wiederhole bis (unendlich) - abwarten, bis eine Zeit t2 abgelaufen ist - LED 2 ausschalten - abwarten, bis eine Zeit t3 abgelaufen ist - LED 2 blinkend einschalten Ob oder was passiert wenn du die Taste nochmals drückst hast du nicht angegeben. Daher wird diese hier auch nicht berücksichtigt
:
Bearbeitet durch User
D. V. schrieb: > Man zählt mithilfe eines Timer eine Variable hoch und leitet davon die > tatsächlich gewünchte Zeit ab. Ja, wenn ich jetzt den Vorteiler auf 1024 setze bei einem Takt von 1Mhz, wie viel Zeit wäre das so "realZeit"? kopfkratzer schrieb: > Und jetzt erkläre mir mal bitte wie Du aus den beiden Timestamps die > zwei Stunden errechnen willst ? geht das nicht oder wie?
Wegstaben Verbuchsler schrieb: > Grundzustand : Keine Taste gedrück, keine LED leuchtet (wahrscheinlich > ist das der Zustand nach dem Einschalten deines Controllers) > dann wird irgendwann die Taste gedrückt, Den Zustand "Taste ist > (verlässlich)gedrückt" bekommst du als Ergebniss deiner > Entprell-Routine. Das Betä#tigen der Taste führt zum sofortigen und > immerwährenden Leuchten von LED1, sowie zum "normalen Lampen-Geleuchte", > welche folgendes macht: > - abwarten, bis eine Zeit t1 abgelaufen ist > - am Ende der Zeit t1 die LED 2 statisch einschalten (so lese ich das > raus aus deinem post) > Wiederhole bis (unendlich) > - abwarten, bis eine Zeit t2 abgelaufen ist > - LED 2 ausschalten > - abwarten, bis eine Zeit t3 abgelaufen ist > - LED 2 blinkend einschalten Das ist es zu 100%. Genau das möchte ich erreichen! Also am besten wäre es noch, wenn t4 existiert, und nach Ablauf dieser Zeitspanne wird die LED 2 komplett abgeschaltet. Wenn ich den Taster nochmals drücke, soll eigentlich nichts passieren (möglicherweise Reset des kompletten Vorgangs, aber das ist kein Muss)
Oldie schrieb: > D. V. schrieb: >> Man zählt mithilfe eines Timer eine Variable hoch und leitet davon die >> tatsächlich gewünchte Zeit ab. > > Ja, wenn ich jetzt den Vorteiler auf 1024 setze bei einem Takt von 1Mhz, > wie viel Zeit wäre das so "realZeit"? > > kopfkratzer schrieb: >> Und jetzt erkläre mir mal bitte wie Du aus den beiden Timestamps die >> zwei Stunden errechnen willst ? > > geht das nicht oder wie? kopftisch Was steht denn im Datenblatt des Mega8 bei Timer-OverFlow ? Wie berechnet sich da die Frequenz ? Nimm einen Taschenrechner und tippe da Deine aktuelle Frequenz und den Vorteilerfaktor ein, was für einen Wert bei 1024 hast Du dann ? Statt Dein angestrebtes Programm empfehle ich Dir erstmal Dich solange mit Timer0 zu beschäftigen bis Du in der Lage bist EINE LED im ungefähren Sekundentakt blinken zu lassen. Dazu brauchst Du eine Zählervariable, besser nimm gleich drei für Sekunden, Minuten und Stunden. Du mußt mit der Formel im Datenblatt den ungefähren Sekundenwert ausrechnen und dann eine volatile Variable damit in der ISR beschicken. Die dann auf Minuten und Stunden umzubrechen ist in C trivial, wenn man denn weiß wie es geht ... Also besser in die nächste Bücherei und sich ein C-Buch holen um das auch wirklich durchzuarbeiten. Wenn dann der Groschen wegen modulo&Co. gefallen ist und Du außer "Hallo Welt" auch z.B. den Verbrauch Deines Mopeds korrekt ausrechnen kannst geht's weiter ;-) Es führen zwar alle Wege nach Rom das wurde aber nicht an einem Tag erbaut :-P
Also, ich habe eine angestrebte Periodendauer von t=7200s (2h) Und bei einem Takt von 4Mhz und einem Vorteiler von 1024 wäre die längstmögliche Periodendauer t0 = ca. 0,0655s. Dann bruache ich von t0 insgesamt 101000 Perioden um meine 2 Stunden zu erreichen, ist das richtig?
Aaalso, mein Problem ist folgendes: ich verstehe nicht, wie ich 2 Stunden im Timer erreiche. Ist es machbar, bei einem Takt von 4 MHZ einen prescaler von 1024 zu benutzen und dann irgendwo mitzählen zu lassen, wie oft ein Interrupt ausgelöst wurde? Also so: 4Mhz mit 1024er Prescaler läuft, dann beginnt er wieder bei 0, wenn ein Durchlauf vollbracht ist und simultan dazu wird in irgendeinem Register mitgezählt, wie viele Durchläufe gemacht wurden. Und wenn die Durchlaufanzahl einer vorher definierten entspricht, wird ein anderes Ereignis ausgelöst. ist das möglich?
Oldie frug:
>ist das möglich?
Na freilich ist das möglich, aber die Ausgangswerte sind nicht so gut
gewählt, um 1Hz zu erzeugen.
Es geht mit hier mit 4MHz los, die vom Vorteiler durch 1024 geteilt
werden.
Das heißt, daß der eigentliche Zähler dann mit 3906,25 Hz getaktet wird.
Wenn Du Timer 0 benutzt, dann hat der (8-Bit Timer) 256 Zählschritte,
bevor er "einmal rum" ist.
Das heißt nun: Die 3906,25 Hz werden durch 256 geteilt. Das wären dann
15,25... Hz.
Das wird Mumpitz....
Besser ist es, ganzzahlige Verhältnisse zu schaffen: Nimm 256 als
Vorteiler.
Dann hast Du 4MHz/64= 62500 Hz.
Man muß im Interrupt dann eine Hilfsvariable die Anzahl der Interrupts
zählen lassen und wenn die entsprechende Zahle erreicht ist, eine Aktion
auslösen:
Hinweis, bevor hier wieder sinnloses Genöle kommt:
Man KANN den Timer auch im CTC-Modus betreiben und braucht ihn dann
nicht vor zu laden. Das dient hier nur zur besseren Verständlichkeit:
1 | $regfile = "2313def.dat" 'AT90S2313-Deklarationen |
2 | $crystal = 4000000 'Quarz: 4 MHz |
3 | Dim Umlauf As Byte |
4 | Dim X As Bit |
5 | On Timer0 Ontimer0 |
6 | |
7 | Config Timer0 = Timer , Prescale = 64 '4Mhz/64 = 62500 Hz |
8 | 'Timer auf 6 'heißt:'250Schritte 'bis Überlauf |
9 | Enable Timer0 'Timer erzeugt 250 Hz |
10 | |
11 | Enable Interrupts 'Interrupts global zulassen |
12 | Timer0 = 6 |
13 | Umlauf = 250 'Umlauf zählt die Interrupts |
14 | Config Portd.6 = Output 'LED an Port D6 |
15 | Portd.6 = 0 |
16 | X = 0 |
17 | |
18 | |
19 | Do |
20 | If Umlauf = 0 Then |
21 | Umlauf = 250 |
22 | If X = 0 Then |
23 | Portd.6 = 0 |
24 | X = 1 |
25 | Else |
26 | Portd.6 = 1 |
27 | X = 0 |
28 | End If |
29 | End If |
30 | Loop |
31 | |
32 | 'Interrupt-Routine |
33 | |
34 | Ontimer0: |
35 | Timer0 = 6 'Timer sofort neu laden |
36 | Decr Umlauf |
37 | |
38 | Return |
39 | ' **** END OF PROGRAM |
:
Bearbeitet durch User
Danke! Nur habe ich folgende Fragen: wo kommen die 250 her? Also woher weiß ich dass der Timer mit 250 Hz taktet? Und: Wie funktioniert das mit dem Umlauf genau? Du hast ihn jetzt als 250 definiert, heißt das, dass er bis 250 zählt und dann ein Ereignis auslöst? Danke
>Nur habe ich folgende Fragen: wo kommen die 250 her? Also woher >weiß ich dass der Timer mit 250 Hz taktet? Die 250 kommen daher, daß der Timer vom Wert 6 (mit dem er vorgeladen wurde) aufwärts bis zum Überlauf zählt. Er macht also nicht 256 Ticks, sondern nur 250. Warum 250? Weil 250*250=62500 ist. Jetzt brauchen wir noch einen "zweiten Mann", der auch bis 250 zählen kann. Das ist die Variable "Umlauf", die aber hier nicht aufwärts gezählt wird, sondern von 250 aus "runterwärts". >Wie funktioniert das mit dem Umlauf genau? Du hast ihn jetzt als >250 definiert, heißt das, dass er bis 250 zählt und dann ein Ereignis >auslöst? Im Interrupt wird die Variable "Umlauf", die zu Anfang auch auf 250 gesetzt wurde, um 1 dekrementiert. Wenn Umlauf 0 ist, dann hat es 250 mal einen Interrupt gegeben. MfG Paul Wir müssen hier fort, weil das die Codesammlung ist, die normalerweise nicht zum Fragen-stellen erlaubt ist....
Oldie schrieb: > Danke! Nur habe ich folgende Fragen: wo kommen die 250 her? Also woher > weiß ich dass der Timer mit 250 Hz taktet? Weil du dann im Zusammenspiel mit dem Vorteiler auf eine ganzzahlige Zahl kommst, wie oft der Timer-Interrupt pro Sekunde ausgelöst wird. Die 250 hast du frei gewählt, weil das in der Nähe von 256 liegt und sich mit einem der Vorteiler schön ausgeht. > Und: Wie funktioniert das mit dem Umlauf genau? Du hast ihn jetzt als > 250 definiert, heißt das, dass er bis 250 zählt und dann ein Ereignis > auslöst? Nein. Von alleine löst da überhaupt nichts aus. WEnn die ISR 250 mal in der Sekunde aufgerufen wird, dann zählt man eben bei jedem Aufruf eine Variable um 1 hoch (oder runter). Ist die Variable bei 250 angelangt (bzw bei 0, wenn runter gezählt wird), dann ist 1 Sekunde vergangen. Denn der Interrupt wird ja 250 mal in der Sekunde ausgelöst. Die Variable ist genau jene 'Umlauf'
:
Bearbeitet durch User
Oldie schrieb: > Wenn ich den Taster nochmals drücke, soll > eigentlich nichts passieren (möglicherweise Reset des kompletten > Vorgangs, aber das ist kein Muss) Überleg dir das gut! Wenn bei einem weiteren Tastendruck nichts mehr passieren soll, hast du Glück. Du brauchst keine Tastendruckerkennung samt Entprellung. Im zweiten Fall benötigst du sie aber. Auch solltest du mal darüber nachdenken, wie es dann eigentlich weiter geht, wenn die Zeiten abgelaufen sind. Was passiert dann? Wie kommt die Schaltung wieder in den Grundzustand?
Also, ich ersetze den Taster durch einen Schließer, sodass bei Drücken des Schließers einfach der Stromfluss aktiviert wird. Das sollte alles erleichtern. Karl Heinz schrieb: > WEnn die ISR 250 mal in der Sekunde aufgerufen wird, dann zählt man eben > bei jedem Aufruf eine Variable um 1 hoch (oder runter). Ist die Variable > bei 250 angelangt (bzw bei 0, wenn runter gezählt wird), dann ist 1 > Sekunde vergangen. Denn der Interrupt wird ja 250 mal in der Sekunde > ausgelöst. > Die Variable ist genau jene 'Umlauf' Wenn bei 250 eine Sekunde vergangen ist, dann sind bei 900000 Interrupts ja eine Stunde vergangen. Ich wollte am Anfang ja ein Auslösen eines Ergebisses bei 1800000 Interrupts. Ich kann aber nicht einfach sagen, dass bei 1800000 Interrupts ein Ergebnis ausgelöst werden soll, da der Controller nur 255 mal zählen kann, richtig? Wie sorge ich jetzt dafür, dass er 1800000 mal zählen kann? Danke
Oldie schrieb: > Wenn bei 250 eine Sekunde vergangen ist, dann sind bei 900000 Interrupts > ja eine Stunde vergangen. Ich wollte am Anfang ja ein Auslösen eines > Ergebisses bei 1800000 Interrupts. Ich kann aber nicht einfach sagen, > dass bei 1800000 Interrupts ein Ergebnis ausgelöst werden soll Können tust du schon. Musst halt für die Variable eine anderen Datentyp nehmen. Aber ... > , da der > Controller nur 255 mal zählen kann, richtig? Wie sorge ich jetzt dafür, > dass er 1800000 mal zählen kann? Danke Wie machen wir es denn im täglichen Leben? Wir zählen ja auch nicht die Sekunden seit Mitternacht. Sondern: 60 Sekunden sind 1 Minute 60 Minuten sind 1 Stunde. Kein Mensch sagt, dass du Zeiten nur in einer einzigen Variablen zählen darfst. Nimmst du halt 3 davon. Eine für Sekunden, eine für Minuten, eine für Stunden. (Wobei man Stunden eventuell nicht braucht. 120 Minuten geht gerade noch, so dass sich jeder darunter 2 Stunden vorstellen kann)
:
Bearbeitet durch User
Karl Heinz schrieb: > Kein Mensch sagt, dass du Zeiten nur in einer einzigen Variablen zählen > darfst. Nimmst du halt 3 davon. Eine für Sekunden, eine für Minuten, > eine für Stunden. Hohoho, also schummel ich mich zu den 1800000 Interrupts? :D Ungefähr so vom logischen: Wenn 250 Interrupts (1s) ausgelöst, zähle irgendeine Variable (s) hoch bis 60. Wenn s = 60; gehe wieder zurück zu s = 0, aber setze Variable m + 1 Wenn m = 120; aktiviere LED an PortD So vom logischen?
Oldie schrieb: > Karl Heinz schrieb: >> Kein Mensch sagt, dass du Zeiten nur in einer einzigen Variablen zählen >> darfst. Nimmst du halt 3 davon. Eine für Sekunden, eine für Minuten, >> eine für Stunden. > > Hohoho, also schummel ich mich zu den 1800000 Interrupts? :D Was heißt da schummeln. Jede Wald und Wiesen Nasenpopel Uhr arbeitet nach diesem Prinzip. So funktinoniert nun mal unsere Zeitrechnug. Ich seh keinen Grund, warum man dieses Prinzip nicht bernehmen soll. Hat sich seit über 2000 Jahren bewährt. Und nur weil du auf große Zahlen, wie 1.8 Mio Interrupts abfährst, muss das nicht für jeden gelten. Ich stell meine Abfrage lieber auf 120 Minuten ein, als auf 1.8 Mio Interrupts. Das kommt auch besser, wenn man mal statt 2 Stunden nur deren anderthalb braucht. Denn das kann ich im Kopf rechnen, dass das 90 minuten sind. Wieviele Interrupts das sind, ist mir hingegen völlig wurscht. Das ergibt sich sowieso von alleine, bis dann irgendwann mal 90 Minuten erreicht sind.
1 | ....
|
2 | |
3 | volatile uint8_t subCnt; |
4 | volatile uint8_t Sekunden, Minuten, Stunden, Tage, Wochen, Jahre, Jahrhunderte; |
5 | volatile uint16_t Jahrtausende, Jahrmillionen; |
6 | |
7 | ISR( ... ) |
8 | {
|
9 | subCnt++; |
10 | |
11 | if( subCnt == 250 ) |
12 | {
|
13 | subCnt = 0; |
14 | Sekunden++; |
15 | |
16 | if( Sekunden == 60 ) |
17 | {
|
18 | Sekunden = 0; |
19 | Minuten++; |
20 | |
21 | if( Minuten == 60 ) |
22 | {
|
23 | Minuten = 0; |
24 | Stunden++; |
25 | |
26 | if( Stunden == 24 ) |
27 | {
|
28 | Stunden = 0; |
29 | Tage++; |
30 | |
31 | if( Tage == 7 ) |
32 | {
|
33 | Tage = 0; |
34 | Wochen++; |
35 | |
36 | if( Wochen == 52 ) |
37 | {
|
38 | Wochen = 0; |
39 | Jahre++; |
40 | |
41 | if( Jahre == 100 ) |
42 | {
|
43 | Jahre = 0; |
44 | Jahrhunderte++; |
45 | |
46 | if( Jahrhunderte == 10 ) |
47 | {
|
48 | Jahrhunderte = 0; |
49 | Jahrtausende++; |
50 | |
51 | if( Jahrtausende == 1000 ) |
52 | {
|
53 | Jahrtausende = 0; |
54 | Jahrmillionen++; |
55 | }
|
56 | }
|
57 | }
|
58 | }
|
59 | }
|
60 | }
|
61 | }
|
62 | }
|
63 | }
|
64 | }
|
brauchst du es noch länger? Ein paar Stufen mehr gingen noch, bis du auf dem Alter des Universums bist. Immerhin: wenn der letzte Dinosaurier auf den Knopf gedrückt hätte, dann würde das klappen, das heute das Licht angeht. 65 Millionen Jahre sind damit schon locker drinnen.
:
Bearbeitet durch User
Muchas Gracias! Ich habe nun die Sache mit den Interrupts und der Zeitrechnung verstanden. Nur stellt sich mir immer von Code-technisch diese Frage: Ich habe nun definiert, nach 2 Stunden ein Ereignis ausgelöst werden soll. wie stelle ich das dar?
Oldie schrieb: > Muchas Gracias! Ich habe nun die Sache mit den Interrupts und der > Zeitrechnung verstanden. Nur stellt sich mir immer von Code-technisch > diese Frage: Ich habe nun definiert, nach 2 Stunden ein Ereignis > ausgelöst werden soll. wie stelle ich das dar? entweder so wie du schreibst, das du eben die Minuten mit 120 vergleichst, oder was ich immer gerne mache: ich dreh den Spiess um um mach eine Countdownuhr, die von einer bestimmten Zeit auf 0 runter zählt und dann eben schaltet, wenn 0 erreicht ist. Ist sicherlich Geschmackssache, aber ich hab immer das Gefühl, dass ich bei einer Countdown-Uhr besser mit mehreren Zeiten im Programm umgehen kann, weil der Endpunkt des Countdowns ja immer 0 ist und ich einfach nur unterschiedliche Startzeiten zuweisen muss.
1 | volatile uint8_t Minuten; |
2 | volatile uint8_t Sekunden; |
3 | |
4 | ISR( ... ) |
5 | {
|
6 | static uint8_t subCnt; |
7 | |
8 | subCnt++; |
9 | if( SubCnt == 250 ) |
10 | {
|
11 | subCnt = 0; |
12 | if( Sekunden > 0 ) |
13 | Sekunden--; |
14 | |
15 | else
|
16 | {
|
17 | Sekunden = 59; |
18 | |
19 | if( Minuten > 0 ) |
20 | Minuten--; |
21 | |
22 | else
|
23 | // ... Schalte LED aus ...
|
24 | PORT..... |
25 | }
|
26 | }
|
27 | }
|
28 | |
29 | int main() |
30 | {
|
31 | ...
|
32 | |
33 | while( 1 ) |
34 | {
|
35 | if( Taster gedrückt && Minuten == 0 ) |
36 | {
|
37 | // ... Schalte LED ein ...
|
38 | PORT..... |
39 | |
40 | // Countdownzeit setzen
|
41 | cli(); |
42 | Sekunden = 0; |
43 | Minuten = 120; |
44 | sei(); |
45 | |
46 | // jetzt läuft die Uhr und zählt die 120 Minuten runter
|
47 | // sind die abgelaufen, dann wird die LED wieder abgeschaltet
|
48 | }
|
49 | }
|
50 | }
|
Ob man jetzt den Schaltvorgang in der ISR macht oder im Hauptprogramm hängt davon ab, wie kompliziert die abhängige Operation ist. Hier ist das einfach, eine LED wird abgeschaltet. Das kann man genausogut in der ISR machen. Bei komplizierteren Aktionen, setzt man sich dann eben ein Flag, dass die Zeit abgelaufen ist und wertet das dann in der Hauptschleife aus. Dieses Grundrezept kann noch beliebig variiert werden. Zb mt mehreren 'Zählvariablen' können auch mehrere 'Countdownds' parallel laufen. Zb ein 5 Sekunden Countdown, der eine andere LED gleichzeitig blinken lässt. Oder mehrere Taster, die 'gleichzeitig' unterschiedliche Zeiträume auf unterschiedlichen LEDs realisieren. etc. etc. Wie gesagt: denk dir was aus! Wie würdest du das ganze mit Papier, Bleistift und einem Summer machen, der im Sekundentakt einen Ton von sich gibt. Der sekündliche Ton entspricht dem Teil in der ISR
1 | ISR( ... ) |
2 | {
|
3 | |
4 | subCnt++; |
5 | if( subCnt == 250 ) |
6 | {
|
7 | subCnt = 0; |
8 | |
9 | .... hier ist der Sekundentakt |
10 | |
11 | }
|
12 | }
|
und mit den gleichen Strategien, mit denen du in der Realität auch operierst, operierst du auch hier. Das ist im wesentlichen nichts anderes. Nur eben in einer Programmiersprache ausformuliert. Und geh davon aus, dass du ein furchtbar schlechtes Gedächtnis hast. Alles was du dir eigentlich merken müsstest (aber wegen des schlechten Gedächntisses nicht kannst), musst du dir eben aufschreiben (daher Papier und Bleistift). Im Programm ist das dann eben eine Variable. Und ja, wenn das bedeutet, dass du dir am Papier notieren musst, ob die LED jetzt blinken oder Dauerleuchten soll, dann bedeutet das eben das du das 'niederschreiben' musst, oder eben in einer Variablen festhalten, was die LED jetzt eigentlich tun soll (0 ist blinken, 1 ist Dauerleuchten, oder so) und du die Variable 'befragen' musst, was jetzt eigentlich passieren soll. Aber mach dir um Gottes Willen immer vorher die Strategie klar, die du anwenden willst. Du kannst dir als 'Ideenlieferant' dich selber nehmen. Denn du kannst das alles perfekt im wirklichen Leben. Einfach hinsetzen und drauflosprogrammieren hingegen führt normalerweise ins Desaster. So gut bist du noch nicht, dass das klappen würde. Erst mal brauchst du immer einen Plan. Und am besten skizzierst du dir diesen Plan erst mal in einfachen Worten.
:
Bearbeitet durch User
Okay dann mach ich das erstmal komplett in Worten: Es gibt: LED1 LED2 Timer0 Schließer Wenn Schließer aktiviert, dann leuchtet LED1 ununterbrochen. Parallel dazu startet Timer0. Der Takt von 4Mhz wird durch einen Prescaler von 64 geteilt. Das bedeutet: 250 abgelaufene Interrupts ^= 1 Sekunde. Wenn 1 Interrupts abgelaufen, dann inkrementiere Variable interrupts um 1. Wenn Variable Interrupts bei 250, dann inkrementiere Variable Sekunde UND setze Variable Interrupts zurück auf 0, aber lass ihn weiterzählen. Wenn Sekunde bei 60, setzte zurük auf 0 und inkrementiere Variable Minute. Wenn Minute = 120, dann leuchtet LED2 auf. Wenn Minute = 140, dann beende leuchten von LED2 + Beende kompletten Vorgang. Ist das so richtig?
Achja uuund: Kann ich die eine LED dauerhaft leuchten lasse, indem ich das einfach in den Code schreibe, oder muss ich das auch irgendwie immer wiederholen?
Oldie schrieb: > Achja uuund: Kann ich die eine LED dauerhaft leuchten lasse, indem ich > das einfach in den Code schreibe, oder muss ich das auch irgendwie immer > wiederholen? Die LEDs sind ja an einem auf "Ausgang" geschalteten Port angeschlossen. Zum Ein- bzw. Ausschalten setzt man das entsprechende Port-Bit auf den gewünschten Zustand. Der Zustand wird dort gespeichert und bleibt solange erhalten, bis er vom Programm geändert (überschrieben) wird. Wenn also das Programm am Port nicht "rummacht", ändert sich die LED nicht. Gruß Dietrich
Danke! > Wenn Schließer aktiviert, dann leuchtet LED1 ununterbrochen. > Parallel dazu startet Timer0. > Der Takt von 4Mhz wird durch einen Prescaler von 64 geteilt. > Das bedeutet: 250 abgelaufene Interrupts ^= 1 Sekunde. > Wenn 1 Interrupts abgelaufen, dann inkrementiere Variable interrupts um > 1. > Wenn Variable Interrupts bei 250, dann inkrementiere Variable Sekunde > UND > setze Variable Interrupts zurück auf 0, aber lass ihn weiterzählen. > Wenn Sekunde bei 60, setzte zurük auf 0 und inkrementiere Variable > Minute. > Wenn Minute = 120, dann leuchtet LED2 auf. > Wenn Minute = 140, dann beende leuchten von LED2 + Beende kompletten > Vorgang. Ist das richtig?
Oldie schrieb: > Danke! > >> Wenn Schließer aktiviert, dann leuchtet LED1 ununterbrochen. >> Parallel dazu startet Timer0. >> Der Takt von 4Mhz wird durch einen Prescaler von 64 geteilt. >> Das bedeutet: 250 abgelaufene Interrupts ^= 1 Sekunde. >> Wenn 1 Interrupts abgelaufen, dann inkrementiere Variable interrupts um >> 1. >> Wenn Variable Interrupts bei 250, dann inkrementiere Variable Sekunde >> UND >> setze Variable Interrupts zurück auf 0, aber lass ihn weiterzählen. >> Wenn Sekunde bei 60, setzte zurük auf 0 und inkrementiere Variable >> Minute. >> Wenn Minute = 120, dann leuchtet LED2 auf. >> Wenn Minute = 140, dann beende leuchten von LED2 + Beende kompletten >> Vorgang. > > Ist das richtig? Du wirst nie weiter kommen, wenn du immer eine Tante zum lulu gehen brauchst. Du hast den µC vor dir, du hast deine Entwicklungsugebung vor dir. Probiers aus. Nicht funktionierende Programme gehören genauso dazu, wie runterfallen zum radfahr-lernen dazugehört. Kaputt machen kannst du nichts. Im schlimmsten Fall funktionierts einfach nicht. Arbeite in SChritten und setz erst mal kleinere Zeiten an. Ob da letzten Endes 2 Minuten steht oder 120, das ist nur eine Zahl. Aber 2 Minuten (oder noch kürzer) ist für dich in der Enwicklungsphase erlebbar. 120 ist es nicht.
1 | #define F_CPU 4000000UL /* 4MHz */ |
2 | |
3 | #include <avr/io.h> |
4 | #include <util/delay.h> |
5 | #include <avr/interrupt.h> |
6 | |
7 | // Defines:
|
8 | #define LED1 (1<<PD5)
|
9 | #define LED2 (1<<PD6)
|
10 | |
11 | volatile uint8_t Minuten; |
12 | volatile uint8_t Sekunden; |
13 | |
14 | |
15 | int main(void) |
16 | {
|
17 | // LED-Pins als Ausgang definieren
|
18 | DDRD |= LED1 | LED2; |
19 | |
20 | // LED1 einschalten
|
21 | PORTD |= LED1; |
22 | }
|
23 | {
|
24 | // Timer 0 konfigurieren
|
25 | TCCR0 = (1<<CS01) (1<<CS00); // Prescaler 64 |
26 | |
27 | // Overflow Interrupt erlauben
|
28 | TIMSK |= (1<<TOIE0); |
29 | |
30 | // Global Interrupts aktivieren
|
31 | sei(); |
32 | {
|
33 | static uint8_t subCnt; |
34 | |
35 | subCnt++; |
36 | if( SubCnt == 250 ) |
37 | {
|
38 | subCnt = 0; |
39 | if( Sekunden > 0 ) |
40 | Sekunden--; |
41 | |
42 | else
|
43 | {
|
44 | Sekunden = 59; |
45 | |
46 | if( Minuten > 0 ) |
47 | Minuten--; |
48 | |
49 | else
|
50 | // ... Schalte LED aus ...
|
51 | PORTD &= LED2; |
52 | }
|
53 | }
|
54 | }
|
55 | |
56 | |
57 | while(1) |
58 | {
|
59 | if( Minuten == 0 ) |
60 | { PORTD |= LED2; |
61 | // ... Schalte LED ein ...
|
62 | |
63 | |
64 | // Countdownzeit setzen
|
65 | cli(); |
66 | Sekunden = 0; |
67 | Minuten = 2; |
68 | sei(); |
69 | |
70 | // Die 2 Minuten laufen doch ab und dann leuchtet die LED oder?
|
71 | }
|
72 | }
|
73 | }
|
74 | }
|
Und was soll dieses Konglomerat aus zusammenkopiertem Code sein? Wo ist deine ISR? Welcher Codeteil gehört in die ISR? Du solltest wirklich erst mal mit was einfacherem anfangen. Das kann ein Blinder greifen, dass du mit dieser Aufgabenstellung noch heillos überfordert bist. Auch einfaches zusammenkopieren von Code will gelernt sein. Solange man nicht versteht, was man da tut, wird das nichts.
:
Bearbeitet durch User
Okay, also ich bin Schritt für Schritt vorgegangen: Als erstes habe ich ganz stumpf versucht, eine LED leuchten zu lassen.
1 | #define F_CPU 1000000UL /* 1MHz */ |
2 | #include <avr/io.h> |
3 | // Defines:
|
4 | #define LED1 (1<<PD5)
|
5 | #define LED2 (1<<PD6)
|
6 | int main() |
7 | {
|
8 | // LED-Pins als Ausgang definieren
|
9 | DDRD |= LED1 | LED2; |
10 | |
11 | // LED1 einschalten
|
12 | PORTD |= LED1; } |
Hat funktioniert, ein Schritt nach vorne. Das mit dem Timer habe ich mittlerweile auch begriffen, nur ist mir folgendes immer noch ein Rätsel: Was bedeutet dieses ISR? Mag nun plump erscheinen, aber diese Frage quält mich. Was hat es damit auf sich? Was macht man damit, bzw. wofür ist es gut? Danke!
Oldie schrieb: > Was bedeutet dieses ISR? - ISR = Interrupt Service Routine - Interrupt: ein Hardware-Ereignis, dass den Programmablauf unterbricht und die ISR anspringt. Am Ende der ISR kehrt der Prozessor wieder an die Stelle zurück, wo das Hauptprogramm unterbrochen wurde. - Bei der hier beschriebener Anwendung ist es der Timer (ein Stück selbständig arbeitende Hardware innerhalb des Mikrocontollers), der z.B. bei Überlauf den Interrupt auslöst. - Der Timer wird also am Anfang des Hauptprogramms entsprechend konfiguriert (durch Einträge in verschidenen Steuerregistern des Timers), dass er z.B. jede Millisekunde eine Interrupt auslöst. Ab diesem Zeitpunkt ist der Interrupt aktiv und die ISR wird jede Millisekunde abgearbeitet - unabhängig vom Hauptprogramm. Ansonsten solltest Du z.B. mal hier lesen: http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial#Programmieren_mit_Interrupts Gruß Dietrich
Okay Leute, ich habe eine Bitte an euch: Vom Ding her habe ich das ganze jetzt mehr oder weniger verstanden, nur bräuchte ich mal einen von euch, der, wenn er die Zeit findet und ein bisschen Lust hat, mir diesen Code schreibt, damit ich das ganze wirklich nachvollziehen kann, da ich noch Probleme damit habe, die einzelnen Abfolgen richtig aufzuschreiben. >> Atmega8 >> Wenn Schließer aktiviert, dann leuchtet LED1 ununterbrochen. >> Parallel dazu startet Timer0. >> Der Takt von 4Mhz wird durch einen Prescaler von 64 geteilt. >> Das bedeutet: 250 abgelaufene Interrupts ^= 1 Sekunde. >> Wenn 1 Interrupts abgelaufen, dann inkrementiere Variable interrupts um >> 1. >> Wenn Variable Interrupts bei 250, dann inkrementiere Variable Sekunde >> UND >> setze Variable Interrupts zurück auf 0, aber lass ihn weiterzählen. >> Wenn Sekunde bei 60, setzte zurük auf 0 und inkrementiere Variable >> Minute. >> Wenn Minute = 120, dann leuchtet LED2 auf. >> Wenn Minute = 140, dann beende leuchten von LED2 + Beende kompletten >> Vorgang. Also eben, dass von Anfang an LED1 (1<<PD5) leuchtet und dass dabei der Timer läuft, der dann nach 2 Stunden (kann man dann ja noch ändern in weniger) LED2 (1<<PD6) anfängt zu leuchten. Wenn es dann aber zu 140 Mintuen gekommen ist, geht LED2 wieder aus. LED1 leutet ununterbrochen. Wie gesagt, wenn mir einer helfen würde, wäre ich extrem begeistert und er wäre der netteste Mensch der Welt, ich bräuchte das einfach mal, um es nachzuvollziehen. Bitte keine Kommentare á la "Mach's dir selbst du BOB", VIELEN DANK!
Wenn mir jemand das in C schreibt, ich nerve nie wieder! Ich bitte euch aus tiefstem Herzen..
Oder anders: Wieso funktioniert das nicht?
1 | #define F_CPU 1000000UL /* 1MHz */ |
2 | #include <avr/io.h> |
3 | #include <avr/interrupt.h> |
4 | |
5 | // Defines:
|
6 | #define LED1 (1<<PD5)
|
7 | #define LED2 (1<<PD6)
|
8 | |
9 | //Variablen für die Zeit
|
10 | volatile unsigned int millisekunden; |
11 | volatile unsigned int sekunde; |
12 | volatile unsigned int minute; |
13 | volatile unsigned int stunde; |
14 | |
15 | int main(void) |
16 | {
|
17 | |
18 | // LED-Pins als Ausgang definieren
|
19 | DDRD |= LED1 | LED2; |
20 | |
21 | // LED1 einschalten
|
22 | PORTD |= LED1; |
23 | |
24 | |
25 | // Timer 0 konfigurieren
|
26 | TCCR0A = (1<<WGM01); // CTC Modus |
27 | TCCR0B |= (1<<CS01); // Prescaler 8 |
28 | // ((1000000/8)/1000) = 125
|
29 | OCR0A = 125-1; |
30 | |
31 | // Compare Interrupt erlauben
|
32 | TIMSK |= (1<<OCIE0A); |
33 | |
34 | // Global Interrupts aktivieren
|
35 | sei(); |
36 | |
37 | while(1) |
38 | {
|
39 | if ( minute == 2 ) |
40 | {
|
41 | PORTD |= LED2; |
42 | |
43 | }
|
44 | }
|
45 | }
|
46 | |
47 | /*
|
48 | Der Compare Interrupt Handler
|
49 | wird aufgerufen, wenn
|
50 | TCNT0 = OCR0A = 125-1
|
51 | ist (125 Schritte), d.h. genau alle 1 ms
|
52 | */
|
53 | ISR (TIMER0_COMPA_vect) |
54 | {
|
55 | millisekunden++; |
56 | if(millisekunden == 1000) |
57 | {
|
58 | sekunde++; |
59 | millisekunden = 0; |
60 | if(sekunde == 60) |
61 | {
|
62 | minute++; |
63 | sekunde = 0; |
64 | }
|
65 | if(minute == 60) |
66 | {
|
67 | stunde++; |
68 | minute = 0; |
69 | }
|
70 | if(stunde == 24) |
71 | {
|
72 | stunde = 0; |
73 | }
|
74 | }
|
75 | }
|
Ist die LED jetzt nur bei minute == 2 an oder auch danach? Wie sag ich, dass er die LED auch danach noch anlassen soll?
Oldie schrieb: > Ist die LED jetzt nur bei minute == 2 an oder auch danach? Wie sag ich, > dass er die LED auch danach noch anlassen soll? Aus deinen Vorstudeien solltest du eigentlich schon gelernt haben, dass normale Output Port Pins nicht eigenmächtig ihren Zustand ändern. Wenn du daher hier
1 | PORTD |= LED2; |
den Pin auf 1 schaltest, dann bleibt der auch auf 1, weil es im ganzen Programm keine Anweisung gibt, die ihn wieder ausschalten würde. Im übrigen hättest du dir die Frage ganz leicht selbst beantworten können. D.h. der Mega hätte sie dir beantwortet. Brenn das Programm rein, lass es laufen und sieh nach wie es sich verhält. Genau deswegen schreibt dir das auch keiner, obwohl es für dir meisten eine Kleinigkeit ist. Wir sind hier kein kostenloses Entwicklungsbüro. In erster Linie eignest du dir die Kenntnisse an und schreibst das Programm. Wenn es momentan noch zu schwer ist, dann schalt 3 Gänge zurück und fang mit etwas einfacherem an. Dann erhebt sich auch die Frage nicht mehr, ob und wie lange ein Portpin nach dem Setzen auf 1 auch auf 1 bleibt. Dann WÜSSTEST du nämlich, dass er das tut. Und zwar so lange, bis eine Anweisung ausgeführt wird, die den Pin wieder auf 0 setzt. Gibt es keine, dann bleibt der Pin bis zum St. Nimmerleinstag auf 1.
:
Bearbeitet durch User
Warum hast du denn jetzt noch Millisekunden eingebaut? am besten fängst du jetzt mal an selbst zu Coden und nicht nur unverstandenes zusammen zu kopieren. und wenn es nicht klappt übst du erstmal ganz normale interrupts mit LEDs und blinken mit nem Timer und dann geht's weiter.
Hallo, ich habe mir den Code nur kurz überflogen: kannst du mir sagen welchen wertebereich unsigned int hat? (Tip die antwort wird nahe an deimen Problem liegen warum es nicht das tutst was du dir gedacht hast. Und ich schließe mich den anderen an, ganz langsam. Und am besten anderen Quellcode nicht abkopieren sondern abschreiben (ich weiß man kommt sich blöd vor) und wenn man eine Zeile nicht versteht in der C referenz bzw. dem Datenblatt nachgucken. Mfg shee2e
>Und am besten anderen Quellcode nicht abkopieren sondern abschreiben
Ich möchte an dieser Stelle widersprechen. Das entscheidende ist nicht,
ob der Code nun kopiert oder abgeschrieben wird. Das entscheidende ist,
dass man einen Code, Ausdruck für Ausdruck, Zeile für Zeile, Schleife
für Schleife nachvollzieht. Unterläßt man das aber dann ist abschreiben
oder kopieren gleichermaßen sinnlos.
Der Rat, Code nicht einfach nur zu kopieren, bezieht sich demgemäß im
Besonderen auf solche Frager hier, die schon Code kopiert haben und das
Nachvollziehen unterlassen haben.
Man mag darüber verschiedener Meinung sein, ob nicht der Rat den Code
nachzuvollziehen sinnvoller sei. Aber es ist für den Leser dann sicher
einfacher einen Code anzusehen und zu erkennen ob der Code verstanden
worden ist, als die sprachlich an sich schon nicht einfache Beschreibung
des Fragers zu untersuchen. Deswegen ist der Rat Code lieber von Grund
auf selbst zu schreiben effektiver.
Hallo, ja ok kopiert oder abgeschreiben ist eigentlich egal, aber nachvollzogen sollte es werden. Da ist das abschreiben für mich besser da ich damals das sicher jede Zeile durchgeganen bin und in dem Fall, dass ich es nicht verstanden habe, sofort nachgeschlagen habe. MfG shee2e
:
Bearbeitet durch User
Jon Doe schrieb: > sollte es werden. Da ist das abschreiben für mich besser Ist bei mir ähnlich. Wenn ich etwas abschreibe, dann bleibt es nicht aus, dass man sich während des Schreibens bereits erste Gedanken macht. Und sei es nur, dass man die generelle Struktur erkennt bzw. ganz nebenbei anfängt die im Programm verwendeten Begriffe bzw. die Nomenklatur sich zu merken. Den Code durchgehen ist zweifellos unabdingbar. Trotzdem ist abschreiben (überhaupt bei so kurzen Programmen) zumindest bei mir in dieser Hinsicht wesentlich effektiver als einfach nur kopieren mittels Copy&Paste.
An sich liegt, zumindest meiner Ansicht nach, das Nachvollziehen sowieso schon sehr nahe; meint: man sollte sowieso auf die Idee kommen das zu tun. Nun, ich wollte darauf hinaus, das jemand der Code kopiert hat und ihn offensichtlich nicht verstanden hat, vermutlich dazu neigt, ihn auch dann nicht nachzuvollziehen wenn er ihn abschreibt. Das jemand wie Du, Karl-Heinz, den Code nachvollzieht, den er abschreibt, bezweifle ich dagegen keinen Augenblick.
Das Tutorial auf dieser Seite ist imho wirklich sehr gut zum Lernen der notwendigsten Dinge. Arbeite doch da erstmal los und du wirst erstaunt sein, wie einfach dein Problem nach ein paar verstandenen Grundlagen ist...
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.