Ich versuche da heute Abend mal etwas zu schreiben. Mit Timern und Interrupts hast du ja noch nichts programmiert?! Ich werde da nämlich eine kleine Interruptroutine schreiben, die dir ein paar Flags für das "Hauptprogramm" bereitstellt, die in unterschiedlichen Zeitabständen gesetzt werden. Die Pausen benötigst du dann nicht mehr, die "verbraten" eh nur Rechenzeit. Wie du mit den "TimerFlags" dann schön arbeiten kannst, erkläre ich dir dann noch.... Aber trotzdem kommst du jetzt nicht um ein Beispiel drum rum
Da das Digitalpoti 3 Pins hat, ist es ein mechanisches Digitalpoti. Der mittlere Pin ist GND, die anderen beiden sind die Quadratursignale. Im hochohmigen Zustand gehen die Signalpegel nach VCC, wenn man die entsprechenden Portpins des AVR auf Input/PullUp schaltet.Ich habe nun noch eine DigitalPoti gefunden, hat 3 Pins, wobei der mittlere Anschluss auf Masse liegt. Was wie und wo ich anschließen muss, solltest du mir dazu vielleicht auch noch mal in "hochdeutsch" erklären
Man kann das Programm mit dem Debugger überprüfen, indem man an bestimmten interessanten Stellen des Programms Breakpoints setzt. Der Debugger hält an den Breakpoints an und man kann sich so den I/O-Bereich, den Inhalt der Register r0 bis r31 und den Inhalt des SRAMs als Memorydump ansehen.Mit der Bedienung von AVR-Studio komm ich auch noch nicht ganz klar (Fachchinesisch ähhh -Englisch ist nicht ganz meine Stärke).... irgendwie kann man sein Programm da doch checken, also zB die Port-Zustände anzeigen lassen usw, und auch Befehl für Befehl ausführen ?! Ich machte es bisher so, dass ich das Programm auf den AVR schrieb, und in der Schaltung testete, ist aber sehr umständlich ....
Du meinst PD1 und PD2. Ja, PD2 ist alternativ der INT0 Interrupteingang, den nutzen wir für den Encoder. PD1 ist frei gewählt, darauf stimme ich die Software ab.Gib es einen bestimmten Grund für die Pins 1 und 2? Oder würdest du nur die Software auf Pin1 und 2 abstimmen wollen?
.org 1 ;*** Extern0 Interrupt ***
rjmp ExtInterrupt0
QuadEncoder: .byte 1
rcall InitPorts ; Ports initialisieren
rcall InitRegisters ; Register initialisieren
[COLOR=DarkRed]rcall InitExtInterrupt0
sei ; SetEnableInterrupt
ldi RegA, 1
sts QuadEncoder, RegA[/COLOR]
InitExtInterrupt0:
in RegA, MCUCR ; Sense Control von INT0 einstellen
sbr RegA, 1<<ISC01 ; fallende Flanke
cbr RegA, 1<<ISC00
out MCUCR, RegA
in RegA, GICR ; GeneralInterruptControlRegister
sbr RegA, 1<<INT0 ; INT0 setzen
out GICR, Reg1
ret
ExtInterrupt0:
push RegA ; RegA auf den Stack
in RegA, SREG
push RegA ; SREG auf den Stack
sbic PIND, PD1 ; Encoder an PD1 (Bei DIP Package ist das Pin11)
rjmp extint0_up
;************************************************
;*** Runterzählen *******************************
lds RegA, QuadEncoder
tst RegA
breq extint0_80 ; wenn 0, dann 80 einstellen
dec RegA ; sonst dekrementieren
sts QuadEncoder, RegA
rjmp extint0_end
extint0_80: ; 80 einstellen
ldi RegA, 80
sts QuadEncoder, RegA
rjmp extint0_end
;************************************************
;*** Hochzählen *********************************
extint0_up:
lds RegA, QuadEncoder
cpi RegA, 80
brsh extint0_0 ; wenn 80 oder höher, dann 0 einstellen
inc RegA ; sonst inkrementieren
sts QuadEncoder, RegA
rjmp extint0_end
extint0_0: ; 0 einstellen
ldi RegA, 0
sts QuadEncoder, RegA
extint0_end:
pop RegA ; SREG und RegA vom Stack holen
out SREG, RegA
pop RegA
reti
lds DisplayNumber, QuadEncoder
;************************************************
;*** Hier noch allg. Funktionen *****************
rcall InitPorts ; Ports initialisieren
rcall InitRegisters ; Register initialisieren
rcall InitExtInterrupt0
sei ; SetEnableInterrupt
ldi RegA, 1
sts QuadEncoder, RegA
[B][COLOR=DarkRed]TesteEncoder:
lds DisplayNumber, QuadEncoder
rcall leddisplay
rjmp testeencoder[/COLOR][/B]
Ja, jedesmal bei einer fallenden Flanke am Pin PD2. Dein Programm wird dann kurz unterbrochen und wenn die Interruptroutine fertig ist, wieder an der Stelle fortgesetzt, wo zuvor unterbrochen wurde. Du meinst mit Timer die Routine Pause100ms? Wenn die Funktion Pause100ms unterbrochen wird, verlängert die sich natürlich, aber da das Ereignis INT0 selten auftritt, merkt man das nicht besonders. Pausen lassen sich auch schön durch Timerinterrups realisieren. Aber eine Pause benötigst du ja jetzt eigentlich nicht mehr, es könnte höchstens sein, dass man noch etwas wegen Prellen des Encoders machen muss.Die Routine wird also bei jedem Interrupt aufgerufen?! Wenn die Routine ausgeführt wurde, geht es dort weiter wo der Interrupt unterbrochen hat?
Bringt nicht jede dortige Routine den Timer durcheinander (Wird ja nicht in meinem Projekt gebraucht, Neugierde)
ja, kannst mich ja informieren, wenn du die Hardware hast und weiter testen möchtest.Also unterbrechen wir hier die Arbeit noch mal kurz, und machen weiter wenn meine Hardware vollständig ist.
Die seriellen Schnittstellen (UART, SPI) und die Timer des AVR erhalten ihren Takt direkt oder über einen entsprechenden Vorteiler vom Systemtakt. Es läuft also alles normal weiter, wenn eine Interruptroutine ausgeführt wird. Du musst nur zum Beispiel dafür sorgen, dass ein via serieller Schnittstelle empfangenes Byte rechtzeitig "abgeholt" wird, sonst wird es eventuell durch ein nachfolgendes Byte überschrieben, aber dafür musst du ja auch sorgen, wenn keine Interrupts auftreten.Bei der Interruptprogrammierung und Timer meinte ich zB "Störungen" an der seriellen Schnittstelle, Uhrzeitabweichungen usw usw, also garnicht mal die Pausenfunktion.
Der Interrupt INT0 (Pin PD2) wird ausgelöst, es scheint so, als würdest du kein Signal vom Pin PD1 erhalten. An dem Pin solltest Du einmal messen, ob beim Drehen des Digitalpotis ein Rechtecksignal anliegt. Prüfe mal, ob der Portpin PD1 als Input mit Pullup geschaltet ist.PD1 und PD2 habe ich auch schon getauscht, ohne dass sich etwas verändert hat.
;*********************************************************************************
;* IncDisplayNumber
;* DecDisplayNumber
;*
;*
;*********************************************************************************
.equ MAX_DisplayNumber = 80 ; Hier den Maximalwert und den Minimalwert für
.equ MIN_DisplayNumber = 0 ; DisplayNumber definieren
IncDisplayNumber:
cpi DisplayNumber, MAX_DisplayNumber
brsh incdn_setmin
inc DisplayNumber
ret
incdn_setmin:
ldi DisplayNumber, MIN_DisplayNumber
ret
DecDisplayNumber:
cpi DisplayNumber, MIN_DisplayNumber
breq decdn_setmax
dec DisplayNumber
ret
decdn_setmax:
ldi DisplayNumber, MAX_DisplayNumber
ret