PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Kann das so funktionieren? ( Lauflicht )



Namenlos
17.12.2008, 15:36
Hallo Leute :idea:


Ich bin hier dabei ein Lauflicht gerade zu Programmieren und ich habe
erstmal dazu diverse Fragen.

1.Kann das vom Code so funktionieren?

2.Wie realiesiert man Warteschleifen?
Ich hab dazu gegoogelt bis zum geht nicht mehr
und wenn ich mir die Codebeispiele durchlese
scheine ich es zu verstehen aber irgendwie bin ich nicht
fähig diese zu verändern bzw. habe ich den Eindruck das ich
doch nicht alles verstanden habe.
Zum Beispiel:


LDI ZH,HIGH(65535)
LDI ZL,LOW(65535)
Zaehl:
SBIW ZL,1
BRNE Zaehl


ZH,ZHL sind 2 Register z.B. R18/R19 , welche die Zahl 65535 ( 256*256 )
bilden.
Die Erklärung zu SBIC
"This instruction tests a single bit in an I/O register and skips the next instruction if the bit is cleared"
Heißt doch so viel das wenn das Register 'leer' ist das der nächste Befehl übersprungen wird.

BRNE versteh ich nicht ganz.
Wenn ich das nun in meinen Programmablauf einbinden möchte muss
ich das ganze nur noch Warten nennen und es noch mit ret erweitern?

Wer wäre so nett und könnte mir den Rest erklären? .... :oops:

Und alle guten Dinge sind ja Drei.
3.Wie kann man einfach das Lauflicht erweitern?
Zum Beispiel das es sich auf Tastendruck in die andere Richtung bewegt
oder oder alles Inventiert ist?
Wobei das mit den Inventieren ja noch geht da man ja ein
neues Register brauch den Inhalt darein kopiert und den Inhalt
inventiert.Aber wie sieht es mit den rest aus?:-k


Hier der Code:
Das rcall Warten ist noch leer da ich noch nicht richtig verstanden
habe wie Warteschleifen funktionieren.
Ich wollte das aber schonmal stehen haben damit ich *wenn es richtig ist*
auch das rcall an der richtigen Stelle sitzt.


Liebe Grüße
Namenlos



.include "m8def.inc"

.DEF Lauf = r16

ldi Lauf,0b11111111
out DDRB,Lauf
;Alle Pins am Port B durch Ausgabe 0b11111111 ins
;Richtungsregister DDRB als Ausgang konfigurieren


Schleife:

ldi Lauf,0b00000000
;Alle Bits Low
out PortB,Lauf
;Ausgabe in PortB


rcall Warten


ldi Lauf,0b00000001
;Erster Port High
out PortB,Lauf
;Ausgabe in PortB


rcall Warten


ldi Lauf,0b00000010
;Zweiter Port High
out PortB,Lauf
;Ausgabe in PortB


rcall Warten


ldi Lauf,0b00000100
;Dritter Port High
out PortB,Lauf
;Ausgabe in PortB


rcall Warten


ldi Lauf,0b00001000
;Vierter Port High
out PortB,Lauf
;Ausgabe in PortB


rcall Warten


ldi Lauf,0b00010000
;Fünfter Port High
out PortB,Lauf
;Ausgabe in PortB


rcall Warten


ldi Lauf,0b00100000
;Sechster Port High
out PortB,Lauf
;Ausgabe in PortB


rjmp Schleife


Warten:



Code-Tags eingefügt (PicNick)

Besserwessi
17.12.2008, 19:05
Erst mal zur Warteschleife:
ZH/ZL sind die Register 30 und 31 (weiss grade nicht in welcher reihenfolge). Das ist aber wohl das kleinste Problem. Der Befehl SBIW ist nicht bei allen AVR Controllern implementiert. Das ist ein spezieller Befehl für eine 16 Bit subtraktion: von der 16 Bit Zahl in ZH/ZL wird das in dem Beispiel jeweils 1 abgezogen.
Das BRNE ist ein normaler bedingter Sprung: Springe wenn Z-Flag nicht gesetz ist, also das Ergebnis der LEtzten Rechnung nicht 0 war.

Der Code ist umständlich könnte aber sonst fast funktionieren. Es fehlt noch die Initialliserung des Stackpointers.

Ein Erweitern des Probgramms ist sicher möglich. Man müßte da irgendwo die Tasten abfragen und dann ggf. in einen anderen Programmteil springen.

Gock
17.12.2008, 19:50
Ja, und:
SBIW (nicht SBIC) setzt das Z-Flag, wenn das Ergebnis der Subtraktion 0 ist. Dann ist "Equal" erfüllt und der Sprung findet nicht mehr statt, dh das Programm läuft einfach weiter, nachdem 65534 Mal gebranched wurde.
Wenn Du ein Unterprog aufrufen willst musst Du innerhalb dessen noch die verwendeten Register retten, sofern Du sie woanders verwenden willst. Dazu sollte man dann lieber ein Buch oä lesen, damit man weiß, was man tut.
Tasten müssen entprellt werden.
Besser wäre es natäurlich den Timer zu benutzen, aber dazu muss man IRQs auswerten.
Anstatt jedes Bitmuster zu speichern, kannst Du auch einfach ein Bit durch den Port "schieben" -> logical ship left oder right (LSL...)bzw, rotate left/right (ror...).
Gruß

Namenlos
18.12.2008, 19:30
Danke für eue Antworten!

Ich persönlich stelle mir nun einige Fragen.
1)Gibt es den Befehl SBIW auch bei einen Mega8 ?

2)Was für ein Stackpointer?
Bzw wie Initialiesiert man den?

3)Das mit den 'Bit durch den Port schieben' muss ich mir mal
genauer anschauen bis ich mal wieder richtig Zeit dafür finde.
Sind ja zum Glück bald Ferien :)

Ich hoffe die Fragen sind nicht zu blöd! :-#

Liebe Grüße
Namenlos

oberallgeier
18.12.2008, 20:03
... Gibt es den Befehl ... auch bei einen Mega8 ...Solche Fragen stellen sich Dir öfters, Anwort gibts dafür im Datenblatt:
http://www.atmel.com/dyn/products/datasheets.asp?family_id=607#760
... nimm Dir die Langfassung, die Summary nutzt nix. In der Langfassung stehen alle (Assembler-) Befehle für den entsprechenden Controller.


... 'Bit durch den Port schieben' ...Schau mal hier, da gibts etliche Tutorials; (https://www.roboternetz.de/phpBB2/zeigebeitrag.php?p=413294#413294) da stehen eigentlich immer die Bitoperationen beschrieben.

Zum Stackpointer solltest Du aber selbst mal die Suchfunktion bemühen. Fast alle Fragen gabs ja schon mal - und dazu auch Antworten.

Namenlos
20.12.2008, 10:23
Huhu :)

Einmal nur ganz kurz.
Habe leider gerade keine Zeit weil ich meiner Schwester beim Umzug
helfe.
Ich wollte aufjedenfall erstmal Danke für eure Beiträge sagen :)
Oft reicht *hoffentlich O:) * ein kleiner Gedankenanstoß um
weiterzukommen.... *g* und wenn ich wieder auf Granistoße
dann werd ich mich wieder melden :)

Liebe Grüße
Namenlos

Namenlos
23.12.2008, 14:41
/Doppelpost

Danke für eure Beiträge ich hab mich mal jetzt wieder daran
gesetzt und es funktioniert sogar :)
Jetzt versuche ich das zu vereinfachen indem ich
das Bit einfach durch den Port schiebe

Und ich hab mit vorgenommen mit Displays und
AD-Wandlern was zu machen.... das kann
ja noch dauern :oops:

Liebe Grüße
Namenlos

Namenlos
10.01.2009, 23:21
Tripplepost....

Hallo Leute,

mir ist nicht ganz klar ob es angebracht ist hier weiter zu schreiben
aber vor kurzen habe ich wieder Zeit um mich mit µC zu beschäftigen und
ich habe mein Lauflicht inzwischen so verkleinert das ich nun
einen 16Bit Timer benutze und ich bei jeden Überlauf einen
Interrupt auslöse indem ich dann an den Port das Bit einfach schiebe.

Meine Frage ist nun:
Wie könnte man das ganze nun erweitern damit es bei Tasterdruck 1 ( Beispiel) schneller wird und bei einen anderen Tasterdruck wieder
Langsamer wird?

Jetzt habe ich den Timer so gewählt das er etwa alle 2 Sekunden
auslöst.

Um das oben genannte zu realiesieren könnte müsste man
den Timer verkleinern oder bei Tastendruck gewisse
Startwerte vorladen.
So das es bei einen 16 Bit Timer nicht 65536 Takte dauert bist
dieser überläuft sondern nur zum Beispiel die hälfte dieser Takte.
Und wie verknüfpt man dies noch mit Tastern damit
diese Aktion bis zum nächsten Tastendruck erhalten bleibt?

Könnte mir da jemand auf die Sprünge helfen bzw. diverse
Gedankenstupser geben? = )

Liebe Grüße
Namenlos

Der jetzige Code
.include "m8def.inc"


.def Arbeit = r16
.def Licht = r17


.org 0x0000 ; Hauptprogramm
rjmp Hauptprogramm
.org OVF1addr ;Timer 1 Interrupt Vector Addresse
rjmp Timer1

Hauptprogramm:

ldi Arbeit, LOW(RAMEND) ; LOW-Byte der obersten RAM-Adresse
out SPL, Arbeit
ldi Arbeit, HIGH(RAMEND) ; HIGH-Byte der obersten RAM-Adresse
out SPH, Arbeit


ldi Arbeit,0b11111111
out DDRC, Arbeit ;Alle Pins am Port C durch Ausgabe 0b11111111 ins
;Richtungsregister DDRC als Ausgang konfigurieren



ldi r16,0b000000100 ;Vorteiler 256 an Timer 1
out TCCR1B,r16 ;Setze Bit

ldi r16, 0b00000100 ;Interrupt Overflow aktivieren
out TIMSK, r16 ;Setze Bit


sei ;Interrupt Aktivieren

ldi Licht,0b00000001 ; =1
out PortC, Licht ;Erste LED an PortC an


Schleife:

rjmp Schleife


Timer1:

rol Licht ;Bits 'schieben'
out PortC, Licht ;Gebe 'Licht' an PortC aus

reti ;Springe zurück

Besserwessi
11.01.2009, 00:44
Für eine variable Frequenz haben die 16 Bit timer den CTC Mode. Da wirkt dann eines der output-compare Register-paare als obere Grenze für den Timer. Der kann dann z.B. nur bis 10000 Zählen.

Bei der Tastenabfrage wird man eine entprellen nutzen müssen, sonst wird eine Taste leicht mehrmals gezählt.

Gock
11.01.2009, 02:08
Genau.
Die Entprellung kannst Du zB dadurch erreichen, dass Du die Taste alle zB 50ms abfragst. Auf diese Zeit stellst Du Deinen Timer ein. Als Blinkfrequenz kannst Du Vielfache davon wählen, wenn Du einen Zähler in die ISR einfügst, der das Bit zB nur jedes 40ste Mal auslöst (40*50ms=2s).
Gruß

Namenlos
11.01.2009, 16:32
So wäre ich mal wieder,

Kurzer Überblick:
Ich hab jetzt alles so gemacht das ich beim Auslösen
des Timer Interuptes +1 in einen Register dazurechne
und diese mit einen anderen Register vergleiche.
Wenn dies zutrifft dann springe ich zu den Unterprogramm
wo ich das Bit einmal durch PortB schiebe und wieder
in die Hauptschleife Springe.

Das Vergleichregister soll mit einen Tastendruck den Wert +16 oder
-16 'gutgeschrieben bekommen' Somit ist das Vergleichregister
mit 17 Werten einzustellen und somit ist die Geschwindigkeit einzustellen.

Jetzt zu meinen Problem:
PD2 und PD3 sind aktiviert und die PullUps auch.
Bei Tastendruck wird entweder -16 und +16
gerechnet.Die Addition ist ein wenig umständlich gelöst O:)
Für die Subthraktion gibt es einen direkt befehl für das addieren
hab ich nichts direktes gefunden.

Oder gibt es noch was zu beachten?
Und kann mal jemand über den Code gucken?
Beim Assembilieren gab es zumal keine Fehler.... \:D/

Edit:
So jetzt habe ich den Code weiter überarbeitet und im Simulator
von AVRStudio funktioniert dieser Super, sogar die Addition
im Vergleichsregister wird aufaddiert und alles stimmt.
Nur wenn ich das in Hardware aufbaue funktioniert
das ganze Nicht.
Aufgebaut ist das ganze auf einen MyAVRBoard+Breadboard.
Die LED's laufen einfach durch aber ein Tastendruck hat keinerlei
ausmaß auf deren Geschwindigkeit.

Die Ports habe ich auch schon gewechselt,statt die Spannung vom LPT
zu nehmen habe ich auch mal einen Akku + den 7806er genommen
und da hat sich auch nichts geändert.
Jetzt bin ich mal gespannt was ihr dazu sagt.

Liebe Grüße
Namenlos



.include "m8def.inc"

.def Arbeit = r16 ;Für die Initialisieung zuständig
.def Licht = r17 ;Werte für das Lauflicht
.def Zaehler = r18 ;Zähler für jeden Interrupt
.def Vergleich = r19 ;Vergleichs Register für den Zähler [ "Referenz" ]

.def Wert = r20 ;Wert für die Addition / Subthraktion
;Für den Vergleichswert

.def Reset = r21


.org 0x0000 ; Hauptprogramm
rjmp Hauptprogramm
.org OVF0addr ;Timer 0 Interrupt Vector Addresse [8 Bit-Timer ]
rjmp Timer1




Hauptprogramm: ;Initialisierung




ldi Arbeit, LOW(RAMEND) ; LOW-Byte der obersten RAM-Adresse
out SPL, Arbeit
ldi Arbeit, HIGH(RAMEND) ; HIGH-Byte der obersten RAM-Adresse
out SPH, Arbeit



ldi Arbeit,0b11111111
out DDRC, Arbeit ;Alle Pins am Port C durch Ausgabe 0b11111111 ins
;Richtungsregister DDRC als Ausgang konfigurieren


ldi Arbeit,0b11111000
out DDRB, Arbeit ;PB0 und PB1 und PB2 als Eingang Aktivieren


ldi Arbeit,0b00000111 ;PB0 und PB1 und PB2 bekommen Pullup Widerstände
out DDRB, Arbeit



ldi Arbeit,0b00000001 ;Vorteiler 1024 an Timer 0
out TCCR0,Arbeit ;Setze Bits [CS02 und CS00]

ldi Arbeit,0b00000001 ;Timer Interupt Aktivieren
out TIMSK,Arbeit ;Setze Bit [T0IE0]



ldi Licht,0b00000001 ; =1
out PortC, Licht ;Erste LED an PortC an


ldi Wert,0b00010000 ;Konstante für das Subtharieren/Addieren [ 16 ]


ldi Vergleich,0b00100000 ;Startwert für das Vergleichsregister
; [ 32 ]

ldi Reset,0b00000000 ;Lösche das Reset Register

sei ;Interrupt Aktivieren

Schleife: ;Hauptschleife



rjmp Schleife


Timer1: ;Aktion beim Timerinterupt

sbic PINB,0 ;Wenn Taster gedrückt PD2 = 0
rcall Addiere

sbic PINB,1 ;Wenn Taster gedrückt PD3 = 0
rcall Subthraiere


sbic PINB,2 ;Wenn Taster gedrückt PD4 = 0
rcall Wiederherstellen




inc Zaehler ;Addiere 1 zum Zähler Register
cp Zaehler,Vergleich ;Wenn der Zähler <= ist als der Vergleich ist
;Springe zu 'Bitschieben'

brge Bitschieben ;Ansonsten:

reti ;Verlasse den Interrupt Handler



Bitschieben: ;Aktion wenn der Vergleich größer war



ldi Zaehler,0b00000000 ;Setze den Zähler Zurück
rol Licht ;Bits 'schieben'
out PortC, Licht ;Gebe 'Licht' an PortC aus

inc Reset ;Erhöhe Inhalt von 'Reset' um +1
cpi Reset,7 ;Wenn Reset= 7 Springe zu Zuruecksetzen

brge Zuruecksetzen ;wenn nicht:



reti ;Verlasse den Interrupt Handler

Zuruecksetzen:



ldi Licht,0b00000001 ;Setze 'Licht' zurück'
out PortC, Licht ;und gebe es in PortC aus

ldi Reset,0b00000000 ;Lösche das Reset-Register

reti ;Verlasse den Interrupt Handler



Addiere:

add Vergleich,Wert ;Addiere 8 zu das Vergleichregister
ret ;Gehe wieder zurück

Subthraiere:
sub Vergleich,Wert ;Subthraiere 8 von dem Vergleichregister
ret ;Gehe wieder zurück


Wiederherstellen:
ldi Vergleich,0b00100000 ;Startwert für das Vergleichsregister
ret ;Gehe wieder zurück

Gock
12.01.2009, 00:06
ldi Arbeit,0b00000111 ;PB0 und PB1 und PB2 bekommen Pullup Widerstände
out DDRB, Arbeit
Ne, so sind es Ausgänge!
DDRB = 0bxxxxx000
und
PORTB = 0bxxxxx111
Gruß

Namenlos
12.01.2009, 17:24
Danke für die Antwort.... a
ber das hat immer noch nicht geändert. :-k
Hat jemand Rat parat?Wäre riesig Dankbar dafür :-({|=


Liebe Grüße
Namenlos

Gock
12.01.2009, 22:54
sbic PINB,0 ;Wenn Taster gedrückt PD2 = 0
Ne, nicht PIN sondern PORT!
Gruß

Namenlos
13.01.2009, 10:08
Hey,

wir sind in der Schule im PC Raum...meine Güte da sind ja viel mehr
Fehler drin als ich dachte :D

Na gut...das werd ich irgendwann noch zum Laufen bekomme :)
Wie schnell soll der Timer sein damit ich die Taster vernüftig
abfragen kann ohne das diese mehrere male gezählt werden?

Vielen Dank für eure Hilfe :)
Heute werde ich das zum laufen bekommen
\:D/

Liebe Grüße
Namenlos

Namenlos
13.01.2009, 15:57
So ich melde mich mal ich hab mir nochmal alles angeschaut und da war der
Wurm wohl drin.

Beim Ersten mal Läut es durch...und danach Leuchten irgendwelche LED's.
Gerade Leuchteten alle bis auf die ersten 2.
Dann Leuchtet nur die Erste...und dann gehen alle nach und nach an bis auf die Letzte.Und dann Leuchten alle bis auf die Erste... ich bin da irgendwie
ziemlich Ratlos.
Im Simulator läuft alles richtig durch wenn ich die Pins entsprechend betätige dauert ein Durchlauf auch länger....und mehrer Durchläufe hab ich mir
auch angeschaut und alles geht.
Kriege ja noch die Krise dabei... ist wohl doch eine Nummer zu groß :-k

Liebe Grüße
Namenlos

Namenlos
13.01.2009, 16:04
Hey danke an euch nochmal :)
Es Läuft jetzt!
Jetzt muss ich nur noch den Timer,Teiler und die ganzen Werte anpassen
damit es richtig gut läuft =D>

Liebe Grüße
Namenlos

Gock
13.01.2009, 18:14
Versuche mal eine Abtastung von 50ms, damit kein Prellen auftritt.
Aber: Wenn Du den Taster länger gedrückt hältst, dann wird es mehrmals erkannt. normalerweise erkennt man bei Tastern zuerst das On, wartet, bis man das Off erkennt und schaltet dann. So kann das nicht passieren...
Viel Spass noch.