PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Attiny13 Frage



Caro
12.09.2012, 09:23
Hallo,

ich beschäftige mich seit kurzem mit der Bascom Programmierung und wollte ein kleines Program mit dem ATTiny13 machen. Das macht aber nicht so wie ich es gern hätte.
Ich möchte mittels eines Tastimpulses ein LED Blinken ein bzw. aus schalten. Hab schon verschiedene Varianten ( Loop Until; While Wend; If Then) versucht komme aber nicht recht weiter.
Vielleicht kann mir mal jemand auch bei einer so banalen Frage helfen.

regfile = "attiny13.dat"
$crystal = 1200000

Config Pinb.1 = Input

Taster Alias Pinb.1

Config Portb.3 = Output
B3 Alias Portb.3

Config Portb.4 = Output
Weiss Alias Portb.4


Dim X As Bit

X = B3

On Int0 Onint0

Config Int0 = Falling
Enable Int0
Enable Interrupts

While X = 1

Toggle Weiss
Waitms 300

Toggle Weiss
Waitms 1000

Toggle Weiss
Waitms 100

Wend

End

Onint0:
Toggle B3

Return


Gruß
Caro

Kampi
12.09.2012, 09:51
Du hast die

Do

Loop

Schleife vergessen.
Dein Programm wird ein mal durchlaufen und dann wars das, sprich der Mikrocontroller prüft ein mal ob das Bit gesetzt ist.
Wenn du einen Interrupt verwendest solltest du den Taster entprellen, da der Mikrocontroller sonst mehrmals in die ISR springt und u.U. bleibt die LED dann aus, weil mit dem letzten Sprung das Bit wieder gelöscht wird.
Siehe hier:

http://www.mikrocontroller.net/articles/Entprellung

Und wenn dann würde ich in der ISR nur ein Bit setzen z.B. so:

Onint0:

Toggle Port_B3_enable

Return

Und im Hauptprogramm dann:

Do
If Port_B3_Enable = 1 then
LED = 1
else
LED = 0
End if
Loop
End

Weil das ist eigtl die schnellste Variante für eine ISR, wenn man in der ISR nur ein Flag setzt oder löscht und dieses Flag dann im Hauptprogramm abfragt.
Bei deiner Anwendung ist das noch nicht kritisch aber solltest du vielleicht im Hinterkopf behalten :=)

Caro
12.09.2012, 10:23
Hallo,

vielen Dank für die schnelle Antwort. Muß erst denken.
Ich dachte die While Wend Schleife ist statt der Do Loop besser geeignet, sollte ja nur durchlaufen werden wenn die Bedingung erfüllt ist, sonst ist Ruhe.

Ich werde mich sicher noch mal melden nachdem meine Denkphase beendet ist

Gruß
Caro

Kampi
12.09.2012, 11:35
Die Do-Loop Schleife ist das Hauptprogramm, sprich quasi ein Rahmen wodrin das eigentliche Programm abgearbeitet wird.
Eine While-Schleife ist ein Element des Hauptprogrammes, ähnlich wie eine If-Abfrage oder ein Pin schalten.
Du kannst das Hauptprogramm natürlich weg lassen nur wenn dann die Bedingung für den Verbleib in der While-Schleife nicht erfüllt ist, springt der Controller aus der Schleife raus und sie beginnt nie wieder von vorne, da der Controller keinen Befehl bekommt das Programm neu auszuführen, da die Do-Loop Schleife fehlt.

Caro
24.09.2012, 17:59
Hallo,

ich muß mich doch noch mal melden. Erst mal vielen Dank für deine Tipps. hat mir sehr geholfen und bin nun auch ganz gut fertig geworden.
Nun habe ich aber noch ein Problem.
Der Interrupt soll die Abarbeitung der Schleife unterbrechen und nach erneuter Umschaltung wieder fort setzen. Das macht sie auch, aber nach dem Interrupt läuft die Schleife noch etwas weiter bevor sie aufhört. Nun habe ich schon nach jedem Toggle eine If Then Abfrage gemacht, so dass die Schleife nach jeder Umschaltung abbricht. Wenn nun aber die Wait Zeit recht lang dauert wartet der Interrupt immer noch bis zum Ende der Wartezeit bevor sie aufhört.
Nun meine Frage: gibt es einen Befehl der, egal wo sich das Program gerade befindet, selbst mitten in einem Waitablauf, die Schleife verlässt bzw. beendet und wenn nötig wieder fort setzt.
Vielen Dank im Voraus

Gruß
H.Jeske

Hab noch das Program vergessen, ist vielleicht hilfreich:

$regfile = "attiny13.dat"
$crystal = 1200000
Config Pinb.1 = Input
Portb.1 = 1
Taster Alias Pinb.1
Config Portb.3 = Output
B3 Alias Portb.3
Config Portb.4 = Output
Weiss Alias Portb.4

On Int0 Onint0
Config Int0 = Falling
Enable Int0
Enable Interrupts
Do
Weiss = 1
If B3 = 1 Then
Toggle Weiss
Wait 5
End If
If B3 = 1 Then
Toggle Weiss
Waitms 300
End If
If B3 = 1 Then
Toggle Weiss
Wait 1
End If
If B3 = 1 Then
Toggle Weiss
Waitms 500
End If
If B3 = 1 Then
Toggle Weiss
Waitms 500
End If
If B3 = 1 Then
Toggle Weiss
Wait 1
End If
Loop
End
Onint0:
Toggle B3
Return

Thegon
24.09.2012, 21:04
Also zur gewünschten Funktionsweise des Programms:
Am Int0 ist ein Taster angeschlossen, und wenn der gedrückt wird, dann sollen bestimmte An - Aus - Sequenzen einer weißen LED durchlaufen werden.
Wenn man den Taster nochmal drückt, dann soll der Durchlauf beendet werden.
Und wenn man den Durchlauf ausschaltet, dann soll die LED sofort ausgehen, und nicht erst nach der Wartezeit?

Man könnt doch einfach in die ISR schreiben:



Onint0:
Toggle B3

If B3 = 0 then
Weiss = 0
End If

Return


Dann würde die LED sofort ausgehen, wenn man den Taster drückt, um den Durchlauf auszuschalten. Das einzige Problem ist, dass man die Wartezeit noch abwarten muss, bis man den Durchlauf wieder einschalten kann.

Eine Warteschleife zu Unterbrechen geht glaub ich nicht so einfach, ich habe zumindest nichts gefunden.
Wenn man es unbedingt braucht, dann muss man entweder auf einen Timer zurückgreifen oder man baut sich eine Warteschleife nach, die eben nur wartet, wenn die Flag auch wirklich gesetzt ist.

Also eine Schleife, die eine Varible runterzählt, und das aber nur, wenn B3 = 1. Wenn B3 = 0 dann hört die "nachgebaute" Schleife auf, zu zählen.
Es wird also überprüft, ob B3 = 1, wenn nein, dann sofort beenden, wenn ja, dann eine Millisekunde warten und von einer Variable eins subtrahieren. Dann das ganze wieder von vorne... (also in einer Do - Loop schleife)

Mfg Thegon

Thomas E.
26.09.2012, 17:38
Ich würde mal versuchen, mittels Goto aus der ISR (BÖSE - ich weiß) zu einem Label vor der Hauptschleife zu springen. Denn wenn du die ISR mit Return verlässt, ist ja klar, dass er mitten in die Warteschleife zurückspringt und sie weiter ausführt.

Searcher
26.09.2012, 18:44
mittels Goto aus der ISR (BÖSE - ich weiß) zu einem Label vor der Hauptschleife zu springen.

Das find ich einen echt gewagten Sprung. Da muß mindestens vorher noch der Stack bereinigt werden, sonst läuft der irgendwann über und das globale Interrupt Enable gesetzt werden, wenn noch weitere Interrupts stattfinden sollen.

Gruß
Searcher

Thegon
26.09.2012, 19:22
Im Prinzip würde hier doch ein einfacher Timer Abhilfe schaffen. Und der ATtimy13 hat doch einen.
Also einfach den Timer so konfiguriern, dass er in der Kleinsten gewünschten Zeit (z.B. 10ms) einen Overflow generiert, und in diesem Dann eine Variable hochzählen. Wenn die variable 1 dann togglen, dann wenn die Variable 2 ist, und dann wenn 4 wieder. Wenn die Variable z.B. 200 erreicht hat (würden im Beispiel 2s entsprechen), dann wird sie wieder auf Null gesetzt, und alles beginnt von vorne. Wenn nun der Interrupt reinkommt, dann wird der Timer ausgeschaltet, die Led ebenfalls sofort ausgeschaltet, und die Variable auf Null gesetzt. Kommt der Interrupt wieder herein, dann wieder Timer aktivieren und los gehts.

Nur bin ich mir nicht sicher, ob sich das vom Speicher ausgeht, der ATtiny13 hat ja nur 64Bytes RAM oder so, aber so groß ist das Programm dann ja auch wieder nicht?

Noch eine Frage: ist der Taster, mit dem der Interrut erzeugt wird (ich nehme einmal an, es ist ein Taster) eigentlich entprellt? Sonst könnten sich da ein paar lustige Effekte ergeben, und man fragt sich, warum der Taster nicht reagiert hat, obwohl der Interupt zwei mal reingekommen ist, einmal aus und gleich wieder an ;-)

Mfg Thegon

peterfido
26.09.2012, 20:07
Normal reichen die 64 Byte für sowas aus. Wie groß ist denn der Stack in den Configs?

Mit einem kleineren Stack lässt sich folgendes compilieren (ungetestet) :

$regfile = "attiny13.dat"
$crystal = 1200000

$hwstack = 16
$swstack = 16
$framesize = 8


Ddrb = &B00011000
Portb.1 = 1
Taster Alias Pinb.1
B3 Alias Portb.3
Weiss Alias Portb.4
Dim Anders As Bit
Dim Wpause As Word

On Int0 Onint0
Config Int0 = Falling
Enable Int0
Enable Interrupts


Do
If B3 = 1 Then
Wpause = 300
Gosub Pause
End If
If Anders = 1 Then
Enable Int0
Waitms 20
Reset Anders
Toggle B3
End If
Loop
End


Pause:
Do
Waitms 1
Decr Wpause
If Anders = 1 Then Return
Loop Until Wpause = 0
Return


Onint0:
Disable Int0
Set Anders
Return

Caro
28.09.2012, 07:11
Hallo,

also ich bin ja begeistert von der Gemeinde, so viele gute Tipps hätte ich gar nicht erwartet.
Also den esten Tipp von Thegon habe ich aus probiert und das kommt meinen Vorstellungen schon sehr Nahe.
Mal sehen, wenn ich Zeit habe werd ich weiter probieren, also vielen Dank an Euch, scheint ja doch ein Thema zu sein das ich da angesprochen hatte.

Gruß
Caro