Forum: Mikrocontroller und Digitale Elektronik BASIC verschiedene Takte mit AT90S2313


von Tobias Blome (Gast)


Lesenswert?

Hallo,
ich hab den AT90S2313 und brauche verschiedene Blinktakte an den
Ausgängen. Also Beispiel: PD6 blinkt mit 20Hz / PD5 blinkt mit 10Hz und
PD4 mit 50Hz oder so in etwa.

Ich programmier noch nicht lange und hab noch keine Idee wie man
soetwas macht. mit dem Wait-Befehl geht das wohl schlcht oder.
Vorschläge bitte in Basic.

Danke schon mal,
Tobias

von Tobias Blome (Gast)


Lesenswert?

Ach so, ich hab noch etwas vergessen:
die Lampen sollen natürlich alle "gleichzeitig" blinken.

Tobias

von ...HanneS... (Gast)


Lesenswert?

Dein Freund ist der Timer-Interrupt. Lass diesen mit dem kleinsten
gemeinsamen Vielfachen deiner Wunsch-Frequenzen "klappern" und
behandle in dieser ISR für jeden "Taktausgang" eine separate
Zählvariable, mit der du den Ausgang steuerst. In ASM ist das kein
Problem, es müsste also auch mit einer Hochsprache zu realisieren
sein...

von Tobias Blome (Gast)


Lesenswert?

ja danke- aber so richtig werd ich daraus nicht schlau. könnte ich da
mal ein Beispiel in Basic bekommen?

Tobias

von ...HanneS... (Gast)


Lesenswert?

Hi...

BASIC kann ich leider nur auf dem Commodore plus/4 und dem PC, bei AVR
leider (oder Gottseidank) nicht.

Aber nochmal zum Problem.
Du möchtest verschiedene Blinkfrequenzen gleichzeitig ausgeben.
Dazu rechnest du dir erstmal eine "Taktfrequenz" aus, die durch alle
deine gewünschten Frequenzen teilbar ist.
Willst du 10Hz, 50Hz und 30Hz, so ist 150Hz schonmal nicht schlecht.
Denn dann hast du als Teiler 15, 3 und 5. 1,5kHz wäre besser, dann
teilt man durch 150, 30 und 50...

Du stellst also Timer0-Vorteiler und Timer0-Startwert so ein, dass
Timer0 alle 6,67ms (1/150Hz) einen Überlauf-Interrupt erzeugt.

In der ISR (Beispiel 150 Hz) musst du dann Folgendes tun:
- SREG sichern (zumindest in Assembler)
- Timer0 auf Startwert setzen (n Takte vor Überlauf)
- die Variable für erste Frequenz runterzählen
  * bei 0 wieder auf Startwert (im obigen Beispiel 15) setzen und
  * den Portpin für Freq.1 toggeln
- die Variable für zweite Frequenz runterzählen
  * bei 0 wieder auf Startwert (im obigen Beispiel 3) setzen und
  * den Portpin für Freq.2 toggeln
- die Variable für dritte Frequenz runterzählen
  * bei 0 wieder auf Startwert (im obigen Beispiel 5) setzen und
  * den Portpin für Freq.3 toggeln
- SREG wiederherstellen (in ASM)

Das Hauptprogramm schickt dann den AVR schlafen oder macht noch anderes
sinnloses Zeugs...
Willst du die Frequenzen flexibel machen, dann setze die ISR-Frequenz
(also die Frequenz der Timer-Interrupts) so hoch, dass du mit größeren
Teilern arbeiten kannst. In ASM würde ich darauf achten, dass der
maximal erforderliche Teiler 255 beträgt, also ein Register als
Variable genügt. Das macht das Programm schnell und überschaubar, denn
eine ISR soll möglichst kurz sein. Wenn es nötig ist, gehen auch
16-Bit-Teiler (also jeweils 2 Register), aber eben nur, wenn unbedingt
nötig.

Brauchst du noch eine Tastaturabfrage, so lass eine weitere
Zählvariable mitlaufen, mit der du alle 100...200ms deinen Eingangsport
abfragst und die Werte mit den zuvor eingelesenen Werten vergleichst, so
hast du gleich eine Flankenerkennung, die die Tasten einigermaßen
entprellt (für Profi-Lösungen siehe Codesammlung).

...HanneS...

von ...HanneS... (Gast)


Lesenswert?

Sorry, mein Rechenbeispiel stimmt nicht, die Zeiten gelten nicht für die
Periode sondern nur für die halbe Periode. Es kommt also nur die halbe
Frequenz heraus. Du musst die ISR-Frequenz also verdoppeln...

von Tobias Blome (Gast)


Lesenswert?

SUPER TOLL - das hab ich schon fast verstanden glaub ich ;-)

1. was ist toggeln?
---
2. nur zu Verständniss:

-Timer0 läuft runter(erste frequenz)
-timer0 wird mit 2. zeit neu gestartet und läuft wieder runter
-timer0 wird mit 3. frequenz neu gestartet und läuft wieder runter
und dann ist ein µC-Zyklus durch und wie/wann wird der Ausgang
gesetzt/rückgesetzt?
oder so:

-Ausgang 1 setzen
-Timer0 läuft runter(erste frequenz)
-Ausgang 1 rücksetzen
-Ausgang 2 setzen
-timer0 wird mit 2. zeit neu gestartet und läuft wieder runter
-Ausgang 2 rücksetzen
-Ausgang 3 setzen
-timer0 wird mit 3. frequenz neu gestartet und läuft wieder runter
-Ausgang 3 rücksetzen


danke schon mal,

Tobias

von ...HanneS... (Gast)


Lesenswert?

Hi...

1. Toggeln ist Umschalten, aus H mach L, aus L mach H, also den
   Pegel am Pin wechseln...

2. Nein, falsch...

Der Timer läuft mit einer festen Frequenz. Damit er das tut, muss man
den (für diese Frequenz notwendigen) Vorteiler einstellen und den Timer
in jeder ISR (Interrupt-Service-Routine) wieder mit dem richtigen
Startwert laden.

Für jeden zu erzeugenden Blinktakt wird eine weitere Variable
gebraucht, zweckmäßigerweise ein Register. Jedes dieser Register wird
in der ISR um 1 vermindert. Wird dabei der Registerwert 0, dann setzt
man das Register wieder auf den für diesen Blinktakt erforderlichen
Startwert und schaltet das Ausgangsbit um.
Dies wird für jeden Blinkausgang getrennt gemacht.

Man kann dabei den ISR-Takt als Zeitnormal sehen, jeder Blinktakt
dauert eben soundsoviele ISR-Takte, wenn die abgelaufen sind, wird von
vorn gezählt.

In ASM sieht die ISR etwa so aus:

timer0ovf:     ;Einsprungpunkt, der als Intvektor eingetragen wird
 in r2,sreg    ;Statusregister sichern
 out tcnt0,r3  ;Register r3 enthält den Timer-Startwert (256-n)
;Blinker 1...
 dec r16       ;R16 um 1 vermindern
 brne label2   ;bei nicht 0 weg hier...
 ldi r16,15    ;Startwert (15) in Register 16 laden
 sbis portb,0  ;Portbit (PB0) gesetzt?
 rjmp label1   ;nein, dann nicht setzen
 cbi portb,0   ;Portpin auf Low setzen
 rjmp label2   ;und weiter...
label1:        ;PB0 war also nicht gesetzt, deshalb
 sbi portb,0   ;Portpin auf High setzen
label2:
;Blinker 2...
 dec r17       ;R17 um 1 vermindern
 brne label4   ;bei nicht 0 weg hier...
 ldi r17,5     ;Startwert (5) in Register 17 laden
 sbis portb,1  ;Portbit (PB1) gesetzt?
 rjmp label3   ;nein, dann nicht setzen
 cbi portb,1   ;Portpin auf Low setzen
 rjmp label4   ;und weiter...
label3:        ;PB1 war also nicht gesetzt, deshalb
 sbi portb,1   ;Portpin auf High setzen
label4:
;Blinker 1...
 dec r18       ;R18 um 1 vermindern
 brne label6   ;bei nicht 0 weg hier...
 ldi r16,3     ;Startwert (3) in Register 18 laden
 sbis portb,2  ;Portbit (PB2) gesetzt?
 rjmp label5   ;nein, dann nicht setzen
 cbi portb,2   ;Portpin auf Low setzen
 rjmp label6   ;und weiter...
label5:        ;PB2 war also nicht gesetzt, deshalb
 sbi portb,2   ;Portpin auf High setzen
label6:
...
 out sreg,r2   ;Statusregister wiederherstellen
 reti          ;fertig... (RETurn from Interrupt)

Das sieht gegenüber BASIC zwar viel aus, ist es aber nicht, denn jeder
Befehl kostet nur 2 Bytes Flash (1 Word) und dauert meist nur ein oder
zwei Takte...

Das Toggeln geht auch noch etwas eleganter, ich habe aber bewusst diese
Form gewählt.

Übrigens kann man den Registern "sprechende Namen" zuweisen, das
macht den Code lesbarer. Mit den Konstanten geht das auch. Ich habe
hier darauf verzichtet, da ich nicht das ganze Programm schreiben
will...

...HanneS...

von ...HanneS... (Gast)


Lesenswert?

Lach...
Typischer Fehler beim Kopieren...
Das zweite "Blinker 1..." muss natürlich "Blinker 3..." heißen...
Aber das erkennt man ja, oder?

von Tobias Blome (Gast)


Lesenswert?

DANKE! Dann werd ich das mal in Basic versuchen - vielen Dank!

Tobias

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.