Forum: Mikrocontroller und Digitale Elektronik Frage zu Lauflicht


von avusgalaxy (Gast)


Angehängte Dateien:

Lesenswert?

Hi. Habe mir einen Code zusammengeschnipselt.

Läuft eigentlich ganz gut. Nun quälen mich noch 4 Fragen. Vielleicht
kann mir jemand weiterhelfen.

1) Hätte ich das Programm anders (besser) machen können?

2) Ich teste R0 auf 0. Wenn R0 0 ist, dann soll er auf neu springen.
   Mit neu setze ich den Z-Pointer wieder auf 0. Funktioniert ja ganz
  gut. Nur was mache ich, wenn ich dann mehrere Tabellen (Lauflichter)
habe? Gibt es keinen anderen Befehl, um den Z-Pointer auf null zu
setzen?

3) Warum muß ich den Z-Pointer 2-mal inkrementieren, um die nächste
Tabelle auszulesen?

4) Warum muß hinter jeder Tabelle ein ,0 stehen?

Gruß avusgalaxy

von crazy horse (Gast)


Lesenswert?

zu 1: anders kann man es immer machen
besser: wozu dienen denn die Nullen im Datenfeld? Kannst du weglassen
und statt dessen adiw zl, 1 benutzen
Ausserdem ist das Bitmuster derart einfach (und noch dazu symmetrisch),
dass du ganz ohne Tabelle mit einfachen Schiebeoerationen zum Ziel
kommen kannst. Aber im Prinzip ist eine Tabelle schon der richtige Weg,
man kann beliebige Muster nehmen, ist flexibler.
zu 2: du kannst Z ja auch mit einer anderen Startadresse laden
zu 3: siehe 1
zu 4: siehe 1

von dave (Gast)


Lesenswert?

1. Ja sicher :) könntest auch ne richtige Lampe damit machen können...
mit allen Sicherheitsmechanismen...

2. Du könntest einfach mit SBIW den Wert, den du hochgezählt hast,
einfach wieder runternehmen.
Wie du da mehrere "Tabellen" anhängen willst, das kann ich mir nicht
denken. Um die nächste Zeile lesen zu können musste deswegen 2x
erhöhen, weil ja immer das Dummy-Byte 0 angehängt ist.
3. Warum schreibste nicht einfach 2 Bytes in eine Reihe, dann würde +1
reichen.
4. Der Flash ist im Wordformat aufgebaut (ein Befehl normalerweise
2Bytes / 1Word). Deswegen muss immer eine gerade Zahl von Bytes da
stehen. Er mäckert ja auch gern über ODD :)

dave

von avusgalaxy (Gast)


Lesenswert?

Hi.
Das Problem mit den nullen ist jetzt geklärt. Schreibe jetzt 2
Bytes.Vorher hatte ich die null geschrieben, weil mich das AVR Studio
aufmerksam gemacht hat, das die nullen fehlen. Aber jetzt gehts.

Mehrere Tabellen (Lauflichter) dranhängen, geht schon. Wenn man z.B.
das Register R20 als Tabellenzähler nimmt, Muß man halt dann so machen,
daß wenn R20=0 dann nimm Tabelle1, wenn R20=1 dann nimm Tabelle2,usw.
Verstehst du?

Tabelle1:
.db 0b10000000,0b00001000
.db 0b01111000,0b00000000

Tabelle2:
.db 0b00001000,0b00010000
.db 0b01000000,0b00000000

Ich glaube, am besten ist es, daß wenn R0=0, das ich zu start springe,
oder?

Vielen Dank für eure Antworten. Ihr habt mir weitergeholfen.

Gruß avusgalaxy

von dave (Gast)


Lesenswert?

Ja, so hätte ichs mir auch gedacht, aber was bringen dir die
unterschiedlichen Tables? Mit deinem Zähler haste auch nur die
Möglichkeit eine nach dem anderen durchzugehen.. könntest auch einfach
eine große machen.

Also bei meinem Mega32 kann man auch den Befehl:
LPM r16, z+
nehmen. Würdest dir das ADIW ersparen. Mach bei "neu" am besten auch
das high-byte rein.. sonst erlebste irgendwann böse Überraschungen :)

dave

von avusgalaxy (Gast)


Lesenswert?

Nehmen wir an. ich kann mit einem Drehimpulsgeber das Register R20 rauf
oder runter zählen.

Wenn dann R20 0 ist dann:

        ldi ZL, LOW(Tabelle1*2)      ;Z-Pointer für Tabelle
        ldi ZH, HIGH(Tabelle1*2)

Wenn dann R20 1 ist dann:

        ldi ZL, LOW(Tabelle2*2)      ;Z-Pointer für Tabelle
        ldi ZH, HIGH(Tabelle2*2)

Wenn dann R20 2 ist dann:

        ldi ZL, LOW(Tabelle3*2)      ;Z-Pointer für Tabelle
        ldi ZH, HIGH(Tabelle3*2)

Tabelle1 ist z.B. ein Lauflicht, was nach links läuft.
Tabelle2 ist z.B. ein Lauflicht, was nach rechts läuft.
Tabelle3 ist z.B. ein Lauflicht, was nach links und nach rechts läuft.

Somit kann ich dann mit meinem Drehimpulsgeber das Lauflicht auswählen,
das mir gefällt.

Nur mit dem Drehimpulsgeber, das ist wieder so eine Sache. Das mit dem
Graycode von Peter, da kann ich nichts anfangen. Ich suche jetzt schon
lange, kann aber für den AVR in ASM nichts finden. Bei den 8051'ern
hab ich es sofort mit Timerabfrage hinbekommen, nur bei den AVR's
schaffe ich es nicht. Weiß da jemand was?

Ach ja, nochwas zu crazy horse: Das Bitmuster ist einfach, war aber nur
ein Beispiel, es werden später noch komplexere.

von ...HanneS... (Gast)


Angehängte Dateien:

Lesenswert?

Hi...

Warum nutzt du Verzögerungsschleifen?
Häng doch alles in einen Timer-Interrupt, dann kannst du später noch
eine Entprellroutine für (Up-Down-) Tasten einbauen, mit denen du
Tabellenauswahl und Tempo ändern kannst.

Zur Tabellenauswahl:
Wenn alle Tabellen gleich groß sind, kannst du den Pointer immer erst
auf die untere Tabelle positionieren und dann so oft den
Tabellenabstand dazuaddieren, welche Tabelle du nutzen willst.

Im Anhang ist ein Lauflicht-Beispiel für den Mega8, ich denke es müsste
dir gelingen, das zu analysieren.

...

von avusgalaxy (Gast)


Lesenswert?

Hallo HanneS

zu den Timern bin ich leider noch nicht gekommen. Eins nach dem
anderen. Danke für das Programm. Werd ich mal anschauen.

Wie ich das mit dem Drehgeber realisieren kann, weißt du auch nicht?

von ...HanneS... (Gast)


Lesenswert?

Hi...

Ich habe mit diesen Incrementgebern noch nix gemacht (eins nach dem
anderen). Ich weiß auch (noch) nicht, inwiweit deren Kontakte prellen
und wie man die vorteilhaft auswertet. Bisher habe ich mir mit
entprellten Tastern geholfen. Anfangs war allerdings das noch kein
richtiges "Entprellen", sondern nur ein Abfragen im Timer-Int,
inzwischen habe ich Peter Danneggers Entprellroutine(n) (Codesammlung)
verstanden und setze diesen Algorithmus auch ein. (Danke, Peter)

Aber ich glaube mich zu erinnern, dass hier im Forum sowas schon mal
lief. Such doch mal nach INCREMENTALGEBER (14 Treffer allein in diesem
Forum), da geht es sicher zu weiteren Informationen.

Drücke dich nicht vor Interrupts, mit Int's werden die Programme meist
einfacher und überschaubarer als ohne. Schiebe lieber den
Drehimpulsgeber noch etwas vor dir her, dessen Auswertung dürfte
leichter sein, wenn du Int's beherrscht. Immer eines nach dem anderen,
aber nicht den dritten Schritt vor dem ersten.

...

von avusgalaxy (Gast)


Lesenswert?

Ja, aber Peter sagt, das es mit den Interuppts nicht geht, oder nur zu
50 %. Beim 8051 habe es mit einem Timer gemacht, hat super
funktioniert.

Aber Danke

Gruß avusgalaxy

von avusgalaxy (Gast)


Lesenswert?

Hm... bei INCREMENTALGEBER findet er garnichts.

von ...HanneS... (Gast)


Angehängte Dateien:

Lesenswert?

Hi...

Missverständnis:
Timer lösen auch Interrupts aus. Ich nenne nunmal alles, was Interrupts
auslöst (was über die Int-Vektoren geht), Interrupt, nicht nur die
externen Pin-Int's.

Wenn Peter meint, mit (ext.) Int geht das schlecht, dann mag es sein,
dass es nicht/schlecht geht, wenn man ein Signal an den ext.Int
anschließt und in dessen ISR die andere Leitung abfragt. Das wird am
Prellen liegen, der Int wird dadurch mehrmals aufgerufen. Du meinst,
mit einem Timer geht es. Ich würde es auch in einem Timer versuchen,
und zwar in der Timer-ISR, die so ziemlich das ganze Programm steuert.


Hier nur einige Treffer aus der Suche:

http://www.mikrocontroller.net/forum/read-1-75090.html#123296
http://www.mikrocontroller.net/forum/read-1-88166.html#88216
http://www.mikrocontroller.net/forum/read-1-88166.html#88194
http://www.mikrocontroller.net/forum/read-1-88166.html#88193
http://www.mikrocontroller.net/forum/read-1-88166.html#88177
http://www.mikrocontroller.net/forum/read-1-88166.html#88173
http://www.mikrocontroller.net/forum/read-1-65263.html#65266

Ich meinte die Suche, nicht die "Suche im Betreff", ist der kleine
Link "Suchen" rechts neben "Forenliste" und "Threadliste".

...

von avusgalaxy (Gast)


Lesenswert?

Dnke, diese Suche kannte ich garnicht..

von Andi (Gast)


Lesenswert?

Hier ein Ausschnitt aus dem Decoder den ich mal gemacht habe:

.set DIPGPin=PinB    ;Port mit Drehimpulsgeber
.set DIPGChA=4       ;Pin mit Channel A
.set DIPGChB=3       ;Pin mit Channel B
.set DIPGBT=2        ;Pin mit Button
.def DIPGAlt=r4      ;Vorriger Zustand von Channel A
.def DIPG=r5         ;Drehimpulsgeber-Aktion. Nach Abfrage löschen
.def ButtonAlt=r6    ;Vorriger Zustand des Buttons

 clr r16             ;1   Ausgaberegister löschen
 in r17,DIPGPin      ;1   Drehimpulsgeber lesen
 mov r18,r17         ;1   und in die Working-Register
 mov r19,r17         ;1   kopieren

 andi r18,1<<DIPGChA ;1   Channel A des Drehgebers ausmaskieren.
 cp r18,DIPGAlt      ;1   Hat es sich verändert?
 breq DrButton       ;1/2 Wenn nicht, dann Button prüfen.
 mov DIPGAlt,r18     ;1   Aktuellen Zustand von Channel A sichern
 lsl r19             ;1   Aus der Kopie des Drehgeberports
 andi r19,1<<DIPGChA ;1   Channel B ausmaskieren.
 cp r18,r19          ;1   Ist Channel A = Channel B?
 breq DrLinks        ;1/2 Wenn ja, dann wurde nach links gedreht
DrRechts:
 ldi r16,1
 rjmp DrButton
DrLinks:
 ldi r16,-1
 rjmp DrButton
DrButton:
 .....
 tst DIPG           ;Wurde vorher abgeholt?
 brne DrExit        ;Wenn nicht, dann Ende
 move DIPG,r16
 reti               ;Bei Aufruf (rcall) von einer ISR dann nur RET

Funktioniert sowohl in einer Timer-ISR sowohl als auch in einer INT-ISR
(Pin-Change).
Zum Enprellen einfach die Pullups aktivieren und 3x ca. 10nF zu GND
schalten ansonsten Entprell-Routine noch davor setzen.
Der Eigentliche Decoder besteht aus 8 ASM-Befehlen.
Es wird einfach nur geprüft, ob sich der Zustand von Channel A
verändert hat.
Ist das der Fall, wird Channel A mit Channel B verglichen.
Ist Channel A = Channel B wurde nach links gedreht, ansonsten nach
rechts.
Auf die Prüfung des Buttons bin ich jetzt nicht näher eingegangen
sollte aber für Dich bald kein Problem sein.
Der Decoder geht mit Drehgebern bei denen jede 2 Kanaländerungen eine
Rastposition ist.

Ansonsten hier noch eine Umsetzung von Peter Dannegers Original in
ASM:

 in r19,DIPGPin      ;1   Drehimpulsgeber lesen
 clr r18
 sbrs r19,DIPGChB      ;if( Phase_A )
 ldi r18,1          ;i = 1;
 sbrc r19,DIPGChA      ;if( Phase_B )
 rjmp DrRead1
 com r18          ;i ^= 3;
 andi r18,1
 ori r18,2
DrRead1:
 sub r18,DIPGAlt      ;i-= enc_last;
 bst r18,0
 brtc DrButton
 add DIPGAlt,r18
 andi r18,2
 subi r18,1
 cpi r18,-1
 breq DrLinks
 cpi r18,1
 brne DrButton

Läuft bestimmt schneller als das C-Original ;-)
Entprellung ist in diesem Code inklusive.
Am Ende dieser Routine ist in r18 entweder 1 für links, -1 für rechts
oder 0 für nix.
Allerdings geht dieser Decoder nur mit Drehgebern welche bei jeder
Kanaländerung eine Rasterstellung hat.
Man muß bei dieser Routine einen 2´er-Divisor einbauen bei Verwendung
von Drehgebern wie z. B. ddm427.

Gruß
Andi

von avusgalaxy (Gast)


Lesenswert?

Hi Andi.

Wenn ich deinen Code in das AVR Studio kopiere, dann kommen Fehler...

move DIPG,r16 kennt er nicht --> mov

die Punkte natürlich..... aber die sind schon weg

Bin leider erst Anfänger, aber wie kann ich den Code jetzt testen?

Habe ihn mal umgeschrieben. Leider noch ohne Timer. Aber könnte es so
gehen?


.include "2313def.inc"

.set DIPGPin=PinB    ;Port mit Drehimpulsgeber
.set DIPGChA=4       ;Pin mit Channel A
.set DIPGChB=3       ;Pin mit Channel B
.set DIPGBT=2        ;Pin mit Button
.def DIPGAlt=r4      ;Vorriger Zustand von Channel A
.def DIPG=r5         ;Drehimpulsgeber-Aktion. Nach Abfrage löschen
.def ButtonAlt=r6    ;Vorriger Zustand des Buttons
main:
 clr r16             ;1   Ausgaberegister löschen
 in r17,DIPGPin      ;1   Drehimpulsgeber lesen
 mov r18,r17         ;1   und in die Working-Register
 mov r19,r17         ;1   kopieren

 andi r18,1<<DIPGChA ;1   Channel A des Drehgebers ausmaskieren.
 cp r18,DIPGAlt      ;1   Hat es sich verändert?
 breq DrButton       ;1/2 Wenn nicht, dann Button prüfen.
 mov DIPGAlt,r18     ;1   Aktuellen Zustand von Channel A sichern
 lsl r19             ;1   Aus der Kopie des Drehgeberports
 andi r19,1<<DIPGChA ;1   Channel B ausmaskieren.
 cp r18,r19          ;1   Ist Channel A = Channel B?
 breq DrLinks        ;1/2 Wenn ja, dann wurde nach links gedreht
DrRechts:
 ldi r16,1
 rjmp DrButton
DrLinks:
 ldi r16,-1
 rjmp DrButton
DrButton:

 tst DIPG           ;Wurde vorher abgeholt?
 brne main        ;Wenn nicht, dann Ende
 mov DIPG,r16
 rjmp main

von Andi (Gast)


Lesenswert?

OK, habe aus meinem Prog ausgeschnitten und etwas hier hinzugefügt.
Wieso kann Atmel move nicht ausschreiben?
Habe irgend wie immer noch den 68000 von früher intus!

Die Routine ist für einen Timer- oder Pin-Change-Interrupt gedacht.
Als Timer so mit 1 bis 5KHz, je nachdem, was sonst noch so alles runter
gerasselt werden soll oder als Pin-Change-Interrupt mit auf- und
absteigender Flanke.
Weiß nicht, ob das im Main so läuft, bis jetzt noch nicht gemacht.
Mußt noch was einbauen was Dir anzeigt ob links oder rechts gedreht
wurde (LED´s?).
Zumindest kann man im Register "DIPG" bei Betätigung des Drehgebers
mit -1 oder 1 feststellen, ob links oder rechts gedreht wurde.
Nach lesen (abholen) des Drehgeberwertes in DIPG sollte DIPG gelöscht
werden damit der nächste Wert reingeschrieben wird.
Wenn Du das so ohne Entprellroutine probieren willst, denk an die 2
Kondensatoren mit 10nF für jeden der beiden Dreh-Kanäle (PB4 und PB3)
und an die Pullups die in DDRB3 und DDRB4 zu aktivieren sind.
Vergiss nicht, den Stackpointer auf RAMEND zu setzen sonst ist kein
RCALL und kein Interrupt möglich.

Wie ich sehe bist Du noch nicht so richtig mit AVR-ASM vertraut und ich
habe keine Ahnung wie weit Du mit den 8051 fortgeschritten warst.
Möchte nur damit sagen das ich nicht mehr zu dem Drehgeber-Beispiel
sagen möchte da ich Dir AVR-ASM nicht unbedingt beibringen will.

Gruß
Andi

PS: Der besagte ISP-Adapter müßte mit Pony-Prog auch in Verbindung mit
8051´ern gehen, zumindest die, die MISO, MOSI und SCK haben.

von avusgalaxy (Gast)


Lesenswert?

Hi, habs jetzt so probiert, nur es läuft nicht ganz sauber. Beim
rechtsdrehen passt alles. Nur beim linksdrehen, flackert manchmal die
rechte LED. Wie kann das sein?


.include "2313def.inc"

.set DIPGPin=PinB    ;Port mit Drehimpulsgeber
.set DIPGChA=4       ;Pin mit Channel A
.set DIPGChB=3       ;Pin mit Channel B
.set DIPGBT=2        ;Pin mit Button
.def DIPGAlt=r4      ;Vorriger Zustand von Channel A
.def DIPG=r5         ;Drehimpulsgeber-Aktion. Nach Abfrage löschen
.def ButtonAlt=r6    ;Vorriger Zustand des Buttons

 ldi r16, RAMEND  ;Stackpointer initialisieren
 out SPL, r16

 ldi r24, 0x00
 out DDRB, r24

 ldi r24, 0x00
 out PORTB, r24

 ldi r24, 0xFF
 out DDRD, r24

main:
 sbi PORTD, 0
 sbi PORTD, 1
 in r17,DIPGPin      ;1   Drehimpulsgeber lesen
 mov r18,r17         ;1   und in die Working-Register
 mov r19,r17         ;1   kopieren

 andi r18,1<<DIPGChA ;1   Channel A des Drehgebers ausmaskieren.
 cp r18,DIPGAlt      ;1   Hat es sich verändert?
 breq DrButton       ;1/2 Wenn nicht, dann Button prüfen.
 mov DIPGAlt,r18     ;1   Aktuellen Zustand von Channel A sichern
 lsl r19             ;1   Aus der Kopie des Drehgeberports
 andi r19,1<<DIPGChA ;1   Channel B ausmaskieren.
 cp r18,r19          ;1   Ist Channel A = Channel B?
 breq DrLinks        ;1/2 Wenn ja, dann wurde nach links gedreht
DrRechts:
 rcall rechts
 rjmp DrButton
DrLinks:
 rcall links
 rjmp DrButton
DrButton:

 tst DIPG           ;Wurde vorher abgeholt?
 brne main        ;Wenn nicht, dann Ende
 mov DIPG,r16
 rjmp main

links:
 cbi PORTD,0
 rcall pause
 sbi PORTD,0
 ret

rechts:
 cbi PORTD,1
 rcall pause
 sbi PORTD,1
 ret

pause:


          ldi  R21, 0x72
schleife1:ldi  R22, 0xF2
schleife2:dec  R22
          brne schleife2
          dec  R21
          brne schleife1

      ret

von Andi (Gast)


Lesenswert?

Da ham mas schon, das böse Prellen!
Hast Du an die beiden Drehgeberkanäle Kondensatoren hingemacht?
Ansonsten Software-Entprellung und das macht man am besten im
Timer-Interrupt so wie die Drehgeberabfrage.
Software-Entprellung ist ne Zeitliche Angelegenheit und hat in einem
Main nix verloren.
Ähm, r16 als Statusbyte für DIPG hast Du weggelassen. Warum?
Die internen Pullups aktiviert man nicht mit 0 sondern mit 1
vorrausgesetz die Portpins sind auf Input (0).

Gruß
Andi

von avusgalaxy (Gast)


Lesenswert?

Kondensatoren sind dran. Hab ext. 2 Pullups (10kohm) dazugeschaltet. Hab
ich jetzt aber geändert
DIPG, für was brauch ich das? Ist das nicht nur für den Taster?

von Andi (Gast)


Lesenswert?

Ursprünglich war DIPG (DrehImPulsGeber) als Hinweis-Register gedacht, ob
und was sich am Drehgeber getan hat (0=nichts, 1=rechts, -1=links und
auch 3=Button gedrückt was hier jetzt nicht dabei ist).
Wenn das im Timer läuft überprüft das Main-Prog DIPG, reagiert
entsprechend darauf und löscht DIPG damit der Decoder bei Bedarf wieder
was reinschreibt.

Gruß
Andi

von avusgalaxy (Gast)


Lesenswert?

Das ist jetzt komisch...

Wenn ich die 2 Kondensatoren wegnehme, dann prellt es fast nichtmehr.

Wie gibts den das?

von crazy horse (Gast)


Lesenswert?

Ich würde an den Drehimpulsgeber sowieso keine Kondensatoren hängen. Das
sind sehr präzise, empfindliche Kontakte. Selbst mit auf 5V geladenen
100n ruiniert man die über kurz oder lang.
Nötig ist es es auch nicht, dass macht man besser per Software.

von Andi (Gast)


Lesenswert?

Warum nicht Kondensatoren dran hängen?
Weis gerade nicht, wer der Hersteller des ddm427 ist, aber der gibt als
Hardware-Entprellung 10K Pullup und 33nF vor.
Also könnte es ca. mit 36K internem Pullup und 10nF das gleiche sein.
Sicher, per Software ist das natürlich evtl. besser und 20 Cent
billiger aber Avusgalaxy sollte vor dem Software-Entprellen erst mal
Schritt für Schritt mit Timer-Ints anfangen da es in einer Main keinen
Sinn macht.

Avusgalaxy: Die Warteschleife die Du aufrufts ist knap 1mS lang (83000
Takte) und möglicher Weise viel zu lang für die Dreencoder-Software.
Verkürze die mal auf 1mS, vielleicht gehts dann besser.
Oder schau das Du mit dem Timer-Int mal anfängts.

Gruß
Andi

von avusgalaxy (Gast)


Lesenswert?

Und mit dem Timer mach ich es dann so, das ich alle ??ms den Drehgeber
abfrage, oder? Oder meinst du anders entprellen?

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.