Hallo, ich bin absoluter MikroController-Einsteiger und möchte nun meine erste kleine Steuerungsaufgabe lösen: PB0 soll für ca. 1 Stunde auf "logisch 1" sein, dann für ca. 15 Sekunden auf "logisch 0" sein, dann wieder für ca. 1 Stunde auf "logisch 1" und sofort (periodisch fortgesetzt). Dazu brauche ich irgendwie einen Timer für 1 Stunde und für 15 Sekunden, alles +- 20%, also nur ungefähr. Als Quarz nehme ich den internen mit 1MHz. Kann mir jemand einen Assembler Code-Schnipsel mit - Timer Initialisierung - Schleifen für die zwei Zeiten kurz schreiben? Im AVR Tutorial und im Netz hab ich mich schon erkundigt, jedoch nichts brauchbares für dieses (ich denke) einfache Problem gefunden. Ich wäre wirklich riesig erfreut, wenn jemand einen Assembler-Code-Schnipsel (ohne drum herum) schreiben könnte, oder mir einen Link sagen könnte. Vielen Dank schon einmal für unterstützende Hilfen. Gruß Jan Purrucker (aus dem Schwaben-Ländle)
Zwar kein vollständiger Code aber ein parr tipps (ohne Gewähr):
1 | ; Timer 0: Overflow IRQ alle CLK/1024/256 Ticks -> 0.262144 Sec |
2 | ldi r16, 0b00000101 ;clk/1024 -> 1,024mSec Periode |
3 | out TCCR0, r16 |
4 | ldi r16, 0b00000010 ; enable overflow irq |
5 | out TIMSK, r16 |
6 | clr r16 ; reset counter |
7 | out TCNT0, r16 |
Damit kommt der Overflow Irq alle 0.262144 Sec. Dann must du im IRQ nur noch feststellen welcher der beiden Zeiten laufen soll und dementsprechend von 0 bis 3600Sec/0.262144 Sec = 13733 oder 0 bis 15Sec/0.262144 Sec = 57 zählen. Wenn der zähler seinen wert erreicht hat zurücksetzen, port umschalten und in einem Register speichern das jetzt der andere Zähler dran ist. als Hauptprogramm braucht du dann nur noch eine endlosschleife, ggf mit einem sleep befehl drin btw: die internen Taktgeneratoren der AVRs sind keine Quarze sondern RC-glieder! Du solltest dir also mal die sache mit dem OSCCAL ansehen...
Danke für die Hilfe! Du hast Recht, es ist ein RC Glied der interne Takt. Der ist relative ungenau. Aber ich brauche die Zeiten wie gesagt nur ungefähr so genau, daher brauche ich auch kein OSCCAL, sondern muß nur die Fuse-Bits entsprechend auf den internen Oszillator einstellen. Die Entscheidung, ob ich bis 57 oder 13733 zähle mache ich dann, indem ich den Status des PB0 abfrage. Ich versuch mich mal demnächst, und frage hier wieder, sollte was nicht funktionieren. Vielen Dank nochmals für die Hilfe. Gruß Jan
Warum ATtiny11? Wäre nich ATtiny12, oder ATtiny13 besser? (tiny11 kann man nur mit assembler programieren...)
Das Problem ist genuegend trivial um mit ASM geloest zu werden.
Ob Zaehler0 oder Zaehler1 laeuft sollte man sich in einer Variablen und nicht in einem Portbit merken.
Das ist sehr einfach zu machen. Du brauchst nur zwei ineinander verschachtelte Software-Teiler. Der eine teilt durch 57 (von 0.262144 s auf 14.9422 s), der zweite von 14.9422 s auf ca. 1 h). Nach dem Zählerstand des zweiten schaltest Du den Portpin: "High" wenn Zählerstand = 0, "Low" wenn Zählerstand = 1, 2, 3 ... 239. Das ist alles.
1 | TOOverflowInterrupt:
|
2 | |
3 | // wird alle 0.262144 s durchlaufen
|
4 | |
5 | inc k |
6 | IF (k=57) |
7 | {
|
8 | // wird alle 57*0.262144 s = 14.9422 s durchlaufen
|
9 | |
10 | k = 0 |
11 | |
12 | inc i |
13 | IF (i=240) |
14 | {
|
15 | i = 0 |
16 | }
|
17 | |
18 | PortState = 0 |
19 | IF (i=0) PortState = 1 |
20 | |
21 | [PortState auf gewuenschten Portpin ausgeben] |
22 | }
|
Hallo AVRFan, vielen Dank für die nette Erklärung. Nur möchte ich jetzt erst einmal Assembler lernen. Könntest du (oder irgendwer hier) mir deshalb bitte diese Schleife in Assembler kurz schreiben. Kann nämlich mit C nicht viel anfangen. Hab auch schon überlegt wie ich es in Assembler mache, aber bin nicht drauf gekommen. Also wenn mir hier jemand weiterhelfen könnte wäre ich wirklich riesig dankbar. Gruß Jan Purrucker
Ohne Garantie ;)
1 | .def state=r19 |
2 | .def counter_k=r20 |
3 | .def counter_i=r21 |
4 | |
5 | . |
6 | . |
7 | . |
8 | . |
9 | |
10 | timerint: |
11 | inc counter_k |
12 | ;counter >= 57 ? |
13 | cpi counter_k, 57 |
14 | brlo int_ende |
15 | ;Counter auf 0 |
16 | ldi counter_k=0 |
17 | inc counter_i |
18 | ;counter = 240 ? |
19 | cpi counter_i, 240 |
20 | brne weiter |
21 | ;counter auf 0 |
22 | ldi counter_i, 0 |
23 | ;state = 1 |
24 | ldi state, 1 |
25 | rjmp int_ende |
26 | weiter: |
27 | ;state = 2 |
28 | ldi state, 2 |
29 | int_ende: |
30 | reti |
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.