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
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
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
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
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
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.
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. ...
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?
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. ...
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
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". ...
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
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
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.
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
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
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?
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
Das ist jetzt komisch... Wenn ich die 2 Kondensatoren wegnehme, dann prellt es fast nichtmehr. Wie gibts den das?
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.
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
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.