C Drehimpulsgeber auswerten

Janiiix3

Aktives Mitglied
28. Sep. 2013
1.333
10
38
Hannover
Sprachen
  1. ANSI C
  2. C#
Hallo :)

Ich möchte in "C" eine Library für die Auswertung eines Drehimpulsgeber´s schreiben.

Nun meine Frage(n)...

- Wie geht man am besten vor?
- Was ist zu beachten?
- Entprellung ? Software | Hardware ?
- PullUp´s ?!

Habt ihr da Vorschläge für mich, wie ich das am besten in "C" umsetzen kann ?

P.S

Datenblatt ist im Anhang :)
 

Anhänge

  • MRL20_MRLC20.pdf
    74,7 KB · Aufrufe: 25
Hallo,

die Sparche, in der du die Auswertung des Drehimpulsgebers programmierst ist geschmacksache.
Du solltest dir überlegen, ob du im Interruptbetrieb oder im Polling arbeiten willst. Ich würde Interruptbetrieb vorziehen.
Im einfachsten Fall wird ein Pin (egal, ob A oder B) auf einen interruptfähigen Eingang gelegt und auf Flanke getriggert (bei jedem Wechsel, ebal ob von L nach H oder H nach L wird ein Interrupt ausgelöst).
In der Interruptroutine kannst du dann die Pegel der beiden Eingänge vergleichen und z.B. eine Variable incrementieren bzw. decrementieren.
Da es sich lt. Datenblatt um optische Drehencoder handelt, sollte entprellen unnötig sein, weiterhin steht im Datenblatt,
Ausgänge TTL- / CMOS-kompatibel - damit sind PullUps auch unnötig.
Falls du aber mal andere Encoder verwendest (mechanische) solltest du die auf jeden Fall entprellen, RC-Glied reicht völlig, PullUps falls erforderlich (je nach Anschaltung).

Gruß
- gp177 -
 
Hi
Ok, hab mir jetzt das Datenblatt nicht angesehen, aber prinzipiel, was ist die maximale Frequenz oder der kürzeste Impuls? Also Impulse pro Umdrehung un dmaximale Drehzahl. Dann erhälst du einen Wert, der dir sagt, ob es im Polling reicht, oder ob Interrupt angesagt ist oder noch was viel schlimmeres...:cool:
Also Angenommen 1000 Imp/Umdr x 6000 U/min = 1000Imp/U x 100 u/ s
U kürzt du raus und erhälst 100kHz oder , da ja ein Impuls eine halbe Periode ansteht, einen High Impuls von in der Zeit von 0,5 µSek.
Da auch eine ISR Zeit für die Bearbeitung braucht und du sicher nicht nuir den Impulsgeber auswerten willst wird es da ganz schön eng, auch wenn von Impuls zu Impusl 1 µSek vergeht. Das sind bei 16 Mhz und einer durchschnittlichen Bearbeitungszeit eines Befehls von 0,1875 µSek grad mal Zeit für 5-6 Befehle. Vielleicht hab ich auch etwas zu hoch gegriffen, aber da wirst du wohl noch mal nachrechnen müssen. Im schlimmsten Fall brauchst du einen separaten Controller, der die Drehzahl aufbereitet.
Gruß oldmax
 
Hi
Ich hätte mir das Datenblatt doch mal ansehen sollen... :eek: Vergiss, was ich da geschrieben gab und machs im Polling. Ich denke nicht, das du auf 100 U/ Sek kommst und selbst dann hättest du ca. 300 Befehle bei 16 MHz.
Gruß oldmax
 
Hallo,

also es ist ein "Optoelektronische Impulsgeber" und damit entfällt schonmal die Entprellung.

- Optoelektronische Impulsgeber Serie MRL20
- MRL 20 ohne Rastung
- MRLC 20 mit Rastung
- 20 Impulse - Kanäle A / B
- Betrieb mit 5V , Variante f. 3,3V optional

Du hast also die beiden Phasensignale A und B die um 90° versetzt sind. Die beiden Signale bilden zusammen einen 2Bit-Graycode. Der hat gegenüber dem normalen Binären Code den Vorteil das sich immer nur ein Bit auf einmal ändert wenn man hoch oder runterzählt. Damit bekommt man keine inkonsistenten Zustände weil sich die gesamte Bitanzahl nicht zum absolut gleichen Zeitpunkt ändert.

Soviel erstmal zur Theorie. Man kann also die beiden Signale als Gray-Code interpretieren und damit dann weiterarbeiten.

Alternativ baut man sich eine Statemachine die die beiden Signale verarbeitet und mit ihrer Logik je nach Aufbau zB ein kippeln im Umschaltzustand oder andere instabile Zustände abfangen kann und die gewünschten Ausgangswerte liefert.

Ich wünsche schonmal viel Spaß beim Knobeln ;) Ich hab das damals mal mit Assembler selber programmiert. Ohne Interrupts und mit Polling und Entprellung. Läuft sehr zuverlässig. Aber nur bei "normalen" Drehzahlen von den kleinen Drehencodern. Mein Programm macht das mit 4Bit-Schieberegistern, ein wenig Bitmanipulation und durch 2-3 Durchlaufzyklen durch die Routine. Es wird auf jeden Fall das Hirn trainieren und dir einiges an logischem Denken abverlangen :cool:

Gruß
Dino
 
Ich wünsche schonmal viel Spaß beim Knobeln ;) Ich hab das damals mal mit Assembler selber programmiert. Ohne Interrupts und mit Polling und Entprellung. Läuft sehr zuverlässig. Aber nur bei "normalen" Drehzahlen von den kleinen Drehencodern. Mein Programm macht das mit 4Bit-Schieberegistern, ein wenig Bitmanipulation und durch 2-3 Durchlaufzyklen durch die Routine. Es wird auf jeden Fall das Hirn trainieren und dir einiges an logischem Denken abverlangen :cool:

Gruß
Dino

Hallo dino03,

Was meinst du mit dem Satz ?
 
Hi Janiiix,

Hallo dino03,

Was meinst du mit dem Satz ?

Damit meine ich diesen Assemblercode den ich vor etwa 6 Jahren mal zusammengeschustert habe ...

Code:
.equ	sr_enca	= 0x0080	; Encoder A-Entprellung (Phase A)
.equ	sr_encb = 0x0081	; Encoder B-Entprellung (Phase B)
.equ	sr_encp = 0x0082	; Encoder P-Entprellung (Push-Button)
.equ	sr_encm = 0x0083	; Encoder Memory (Ergebnis AB-Aktuell/Zuletzt)
.equ	sr_enct = 0x0084	; Encoder Toggle (Ergebnis Push-Button Aktuell/Zuletzt)
.equ	sr_encc = 0x0085	; Encoder Counter (+/- ueber Drehung)
.equ	sr_encd = 0x0086	; Encoder Diff (+1/0/-1 ueber Drehung)

; ==================================================================
; ===== Encoder-Daten verarbeiten ==================================
; ==================================================================
encoder:
	push r19			; r19 auf Stack retten (fuer wiederherstellung)
	push r20			; r20 auf Stack retten (fuer wiederherstellung)
	push r21			; r21 auf Stack retten (fuer wiederherstellung)
	push r22			; r22 auf Stack retten (fuer wiederherstellung)

; r19 -- Eingabe Encoder-Port , Ergebnis Tastenentprellung (Bit6 fuer Pushbutton)
; r20 -- A/B/P-Entprellung , Differenz
; r21 -- Ergebnis AB-Aktuell/Zuletzt (Statemachine) ,
;		 Ergebnis C-Aktuell/Zuletzt (Flankenerkennung)
; r22 -- Zaehlwert , Encoder-Statemachine Nibble-Rettung
;
; r20 00001111<-A
; r20 00000011<-A
;         ||||
;          \\\\_ 0000=0, 1111=1 => 4Zyklen-Entprellung (oder auch mehr) 
;
; == Rechts == Uhrzeigersinn ==
;	
; B ___________------------____________------------______ R - Rastung
;     |  :  |  :  |  :  |  :  |  :  |  :  |  :  |  :  |   1 - 1/4
; A _____------------____________------------____________ 2 - Halb
;     |  :  |  :  |  :  |  :  |  :  |  :  |  :  |  :  |   3 - 3/4
;     2  :  3  :  R  :  1  :  2  :  3  :  R  :  1  :  2   : - Flanken
;        :     :     :     :     :     :     :     :        
; B   0  0  0  1  1  1  1  0  0  0  0  1  1  1  1  0  0   Bit3 aktuell
; A   0  1  1  1  1  0  0  0  0  1  1  1  1  0  0  0  0   Bit2________ 
; b   0  0  0  0  1  1  1  1  0  0  0  0  1  1  1  1  0   Bit1 
; a   0  0  1  1  1  1  0  0  0  0  1  1  1  1  0  0  0   Bit0 zuletzt
; ->->-> 4  5>13 15 11 10  2  0  4  5>13 15 11 10  2 ->->->
;             ++                      ++                  inc
;   
; == Links == Gegen-Uhrzeigersinn ==
;	
; B _____------------____________------------____________ R - Rastung
;     |  :  |  :  |  :  |  :  |  :  |  :  |  :  |  :  |   1 - 1/4
; A ___________------------____________------------______ 2 - Halb
;     |  :  |  :  |  :  |  :  |  :  |  :  |  :  |  :  |   3 - 3/4
;     2  :  3  :  R  :  1  :  2  :  3  :  R  :  1  :  2   : - Flanken
;        :     :     :     :     :     :     :     :        
; B   0  1  1  1  1  0  0  0  0  1  1  1  1  0  0  0  0   Bit3 aktuell
; A   0  0  0  1  1  1  1  0  0  0  0  1  1  1  1  0  0   Bit2________
; b   0  0  1  1  1  1  0  0  0  0  1  1  1  1  0  0  0   Bit1 
; a   0  0  0  0  1  1  1  1  0  0  0  0  1  1  1  1  0   Bit0 zuletzt
; ->->-> 8 10>14 15  7  5  1  0  8 10>14 15  7  5  1 ->->->
;             --                      --                  dec
; 
	lds r19,sr_541e		; Encoder-Input aus SRAM-Puffer holen

	; =========================================
	; ========== ENCODER-BEARBEITUNG ==========
	; =========================================

	; ===== Statemachine vorbereiten =====
	lds r21,sr_encm		; Memory Encoder-Statemachine <- SRAM
	cbr r21,0b11110000	; uraltes gerettetes Nibble vernichten
	mov r22,r21			; alten Komplettwert retten
	swap r22			; Nibbles tauschen (alten Komplettwert in Bits 7-4)
	lsr r21				; 2 Bits nach rechts ( ab00 -> 00ab )
	lsr r21				; Auf Position fuer letzte Abfrage

	; ===== A entprellen =====
	lds r20,sr_enca		; Entprellung Phase A <- SRAM
	bst r19,0			; Bit 0 von r19 in T-Bit setzen
	sec					; Carry setzen
	brbs 6,a_on			; Branch if Bit6 (T) ist set
	clc					; Carry loeschen
a_on: 	rol r20			; Carry ins Entprell-Reg nach links einrotieren
	cbr r20,0b11110000	; Maske fuer ON-Zyklen
			; ||||||||	; Bei 4Zyklen-Entprellung => Maske 0x11110000 / Test 0x00001111
	cpi r20,0b00001111	; r20 auf 0b00001111 testen (A x Zyklen on)
	brne a_on1			; springen wenn nicht gleich
	sbr r21,0b00000100	; Bit 2 in r21 setzen (A an und entprellt) -> Statemachine

a_on1:	cpi r20,0		; r20 auf 0b00000000 testen (A x Zyklen off)
	brne a_on0			; springen wenn nicht gleich
	cbr r21,0b00000100	; Bit 2 in r21 loeschen (A nicht an und entprellt) -> Statemachine
a_on0:
	sts sr_enca,r20		; Entprellung Phase A -> SRAM


	; ===== B entprellen =====
	lds r20,sr_encb		; Entprellung Phase B <- SRAM
	bst r19,1			; Bit 1 von r19 in T-Bit setzen
	sec					; Carry setzen
	brbs 6,b_on			; Branch if Bit6 (T) ist set
	clc					; Carry loeschen
b_on: 	rol r20			; Carry ins Entprell-Reg nach links einrotieren
	cbr r20,0b11110000	; Maske fuer ON-Zyklen
			; ||||||||	; Bei 4Zyklen-Entprellung => Maske 0x11110000 / Test 0x00001111
	cpi r20,0b00001111	; r20 auf 0b00001111 testen (B x Zyklen on)
	brne b_on1			; springen wenn nicht gleich
	sbr r21,0b00001000	; Bit 3 in r21 setzen (B an und entprellt) -> Statemachine

b_on1:	cpi r20,0		; r20 auf 0b00000000 testen (B x Zyklen off)
	brne b_on0			; springen wenn nicht gleich
	cbr r21,0b00001000	; Bit 3 in r21 loeschen (B nicht an und entprellt) -> Statemachine
b_on0:
	sts sr_encb,r20		; Entprellung Phase B -> SRAM


	; ===== Statemachine erweitern =====
	add r21,r22			; altes gerettetes Nibble hinzuaddieren
						;   altes _____ _____aktuelles Nibble
						;         AB ab AB ab
						;         01 01 11 01 -  5/13 = 0x5D -> rechts = inc
						;         10 10 11 10 - 10/14 = 0xAE -> links  = dec
	sts sr_encm,r21		; Memory Encoder-Statemachine -> SRAM


	; ===== Statemachine abfragen =====
	clr r20				; Diff auf 0x00 (+1/0/-1 => 2er Complement => 0x01/0x00/0xFF)
	lds r22,sr_encc		; Encoder Counter (8Bit) <- SRAM
	cpi r21,0x5D		; r21 auf 0x5D testen (Rechts herum)
	brne nrechts		; springen wenn nicht gleich (nicht rechts -> links oder nix)
	inc r20				; Diff = +1 (0x01)
	inc r22				; 8Bit-Counter +1
	rjmp nlinks			; rechts rum ist abgearbeitet -> weiter
nrechts:
	cpi r21,0xAE		; r21 auf 0xAE testen (Links herum)
	brne nlinks			; springen wenn nicht gleich (nicht links -> bleibt nix)
	dec r20				; Diff = -1 (0xFF)
	dec r22				; 8Bit-Counter -1
nlinks:
	sts sr_encd,r20		; Encoder Diff -> SRAM
	sts sr_encc,r22		; Encoder Counter (8Bit) -> SRAM
	; State-Machine wird ab hier nicht mehr benoetigt -> r21 wieder frei



	; =============================================
	; ========== PUSH-BUTTON-BEARBEITUNG ==========
	; =============================================

	; ===== Flankenerkennung vorbereiten =====
	lds r21,sr_enct		; Memory Push-Button Flankenerkennung <- SRAM
	cbr r21,0b11111100	; ueberschuessiges sicherheitshalber vernichten
	lsr r21				; Auf Position fuer letzte Abfrage ( p0 -> 0p )

	; ===== P entprellen =====
	bst r19,2			; Bit 1 von r19 in T-Bit setzen
	lds r20,sr_encp		; Entprellung Push-Button <- SRAM
	lds r19,sr_keys		; Ergebnis Tasten-Entprellung <- SRAM
	sec					; Carry setzen
	brbs 6,p_on			; Branch if Bit6 (T) ist set
	clc					; Carry loeschen
p_on: 	rol r20			; Carry ins Entprell-Reg nach links einrotieren
	cbr r20,0b11110000	; Maske fuer ON-Zyklen
			; ||||||||	; Bei 4Zyklen-Entprellung => Maske 0x11110000 / Test 0x00001111
	cpi r20,0b00001111	; r20 auf 0b00001111 testen (P x Zyklen on)
	brne p_on1			; springen wenn nicht gleich
	sbr r21,0b00000010	; Bit 3 in r21 setzen (P an und entprellt) -> Flankenerkennung
	sbr r19,0b01000000	; ebenso Bit 6 in r19 setzen -> Ergebnis Tastenentprellung

p_on1:	cpi r20,0		; r20 auf 0b00000000 testen (P x Zyklen off)
	brne p_on0			; springen wenn nicht gleich
	cbr r21,0b00000010	; Bit 3 in r21 loeschen (P nicht an und entprellt) -> Flankenerkennung
	cbr r19,0b01000000	; ebenso Bit 6 in r19 loeschen -> Ergebnis Tastenentprellung
p_on0:
	sts sr_encp,r20		; Entprellung Push-Button -> SRAM
	sts sr_enct,r21		; Memory Push-Button Flankenerkennung -> SRAM
	sts sr_keys,r19		; Ergebnis Tasten-Entprellung -> SRAM


	; ===== Flankenerkennung abfragen =====
	cpi r21,0x02		; r21 auf 0x02 testen (gedrueckt --__ )
	brne npress			; springen wenn nicht gleich (nicht gedrueckt -> losgelassen oder nix)
						; WAS TUN #######################################
	rjmp nrelease		; gedrueckt ist abgearbeitet -> weiter
npress:
	cpi r21,0x01		; r21 auf 0x01 testen (losgelassen __-- )
	brne nrelease		; springen wenn nicht gleich (nicht losgelassen -> bleibt nix)
						; WAS TUN #######################################
nrelease:



	pop r22				; r21 wiederherstellen
	pop r21				; r21 wiederherstellen
	pop r20				; r20 wiederherstellen
	pop r19				; r19 wiederherstellen
	ret					; Subroutine Ende

Gruß
Dino
 
Was bedeutet denn "Rastung" genau ?
Das er in den "nächsten Schritt / Umdrehung" hörbar "einrastet" ? Also wenn das damit gemeint ist, kann ich es hören und fühlen...
 
Hi,

Was bedeutet denn "Rastung" genau ?
Das er in den "nächsten Schritt / Umdrehung" hörbar "einrastet" ? Also wenn das damit gemeint ist, kann ich es hören und fühlen...

ich weiß nicht mehr genau was ich da für nen Encoder verwendet habe. Müßte ich erstmal nachsehen. Kann sein das er nur nach einem kompletten Phasendurchlauf in der nächsten Raststellung (dieses Geklicker beim drehen) war.

Es gibt Encoder die bei jeder Raststellung einen vollen Phasendurchlauf beider Signale durchgeführt haben und manche haben nur einen halben oder einen viertel Durchlauf durchgeführt. Manche haben auch garkeine Rastungen und drehen komplett frei.

Gruß
Dino
 
okay :)

Ich werde es jetzt die Tage mal versuchen & bestimmt wieder auf dich / euch zurück kommen ;)

Vielen dank erstmal
 
... diesen Assemblercode den ich vor etwa 6 Jahren mal zusammengeschustert habe ...
Die ganze Encodiererei sehe ich mir später mal an, wenn ich Ruhe habe, was mir aber mal aufgefallen ist ist Deine "Entprellung":
Du hast ja im SRAM 'n Byte mit dem aktuellen Zustand der 3 Beine (A, B, P), um die jetzt in die Entprell-Bytes einzurollen verwendest Du jeweils:
  • entsprechendes Bit nach T kopieren (BST)
  • Carry setzen (SEC)
  • abhängig von T springen (BRBS)
  • Carry löschen (CLC)
  • Carry einrollen (ROL)
Effektiv kopierst Du das entsprechende Bit ins Carry, und rollst.
Du überspringst mit dem Branch ja nur eine Instruktion (CLC), sollte das dann nicht auch so gehen?
  • Carry setzen (SEC)
  • abhängig vom entsprechenden Bit nächste Intstruktion überspringen (SBRS)
  • Carry löschen (CLC)
  • Carry einrollen (ROL)

Direkt auf die Beinchen (A,B,P) zuzugreifen (mit SBIS) wäre zu heikel? Mit der Kopie ins SRAM und der Verarbeitung von dort her hast Du dann ja quasi 'ne statische Momentaufnahme - bei dem direkten Zugriff lägen ja einige Takte zwischen A- und B-Auswertung (P sollte da ja nicht so kritisch sein), wo die Zustände tanzen könnten

Jaja, Peanuts, ich weiß....
 
Hi LotadaC,

... was mir aber mal aufgefallen ist ist Deine "Entprellung":
Du hast ja im SRAM 'n Byte mit dem aktuellen Zustand der 3 Beine (A, B, P), um die jetzt in die Entprell-Bytes einzurollen verwendest Du jeweils:
  • entsprechendes Bit nach T kopieren (BST)
  • Carry setzen (SEC)
  • abhängig von T springen (BRBS)
  • Carry löschen (CLC)
  • Carry einrollen (ROL)
Effektiv kopierst Du das entsprechende Bit ins Carry, und rollst.
Du überspringst mit dem Branch ja nur eine Instruktion (CLC), sollte das dann nicht auch so gehen?
  • Carry setzen (SEC)
  • abhängig vom entsprechenden Bit nächste Intstruktion überspringen (SBRS)
  • Carry löschen (CLC)
  • Carry einrollen (ROL)

Direkt auf die Beinchen (A,B,P) zuzugreifen (mit SBIS) wäre zu heikel? Mit der Kopie ins SRAM und der Verarbeitung von dort her hast Du dann ja quasi 'ne statische Momentaufnahme - bei dem direkten Zugriff lägen ja einige Takte zwischen A- und B-Auswertung (P sollte da ja nicht so kritisch sein), wo die Zustände tanzen könnten

Jaja, Peanuts, ich weiß....

Die Routinen sind über 6 Jahre alt. Also absolute Anfangszeit mit den Atmels :rolleyes:
Da könnte man bestimmt was optimieren wenn man sich das mal genauer ansieht. Dafür müßte ich mich aber erstmal wieder in den Code reinarbeiten. Alleine bei der Bitschieberei für den Drehencoder hab ich 2-3 Tage Gehirnschmalz reingesteckt wie man das nun am besten lösen könnte. Irgendwann mal ... ;)

Gruß und schöne Ostern
Dino
 
Verdrahtet ist er... Wenn ich nun nach "links" oder "rechts" drehe, leuchten auch meine LED´s wie gewünscht.

Nach rechts : LED 1 an --> LED 2 an
Nach links : LED2 an --> LED 1 an...

Wie werte ich nun am besten die "Drehrichtung" aus ?
Interrupt, hört sich ja schon mal ganz gut an. Ich muss wahrscheinlich meine beiden Zustände (Phase_A & Phase_B) in eine Variable ablegen & jenachdem welche "Reihnfolge" der Controller erkennt (nach links || rechts) die jeweilige LED anschalten!

Ist das so vom Prinzip richtig ?


Code:
/************************************************************************************************************
*								    	Drehimpulsgeber (Optisch)											*
*								   __________________________________										*
*																											*
*			    			- Auswerten eines Drehimpulsgeber´s (Drehencoder)								*
*																											*
* 																											*
*										MRL - 20 C	(ohne Taster)					         				*
*																											*
************************************************************************************************************/



#define Phase_A ((PIND & (1<<PIND6))) // Phase A
#define Phase_B ((PIND & (1<<PIND4))) // Phase B



#include <avr/io.h>

int main(void)
{
	
	PORTD |= ((1<<PD4) | (1<<PD6)); // PullUp´s aktivieren
	DDRB  |= ((1<<PB0) | (1<<PB1)); // Ausgänge für LED´s
	
    while(1)
    {

		if (Phase_A)
		{
			PORTB |= (1<<PB0);
		}
			else
			
		{
			PORTB &= ~(1<<PB0);
		}
		
		if (Phase_B)
		{
			PORTB |= (1<<PB1);
		}
		else
		
		{
			PORTB &= ~(1<<PB1);
		}		
		

    }
}
 
Hallo Janiiix,

du könntest Kanal A an einen Ext Interrupt anschließen und Sensing auf fallende Flanke einstellen. Tritt der Interrupt auf, überprüfst du in der ISR den Zustand von Kanal B (angeschlossen an beliebigem freien IO Pin). Der Zustand von Kanal B gibt dann die Drehrichtung an.

Oder Kanal B an Ext Interrupt, dann allerdings Sensing auf steigende Flanke. Und in der ISR Kanal A prüfen, was dir die Drehrichtung angibt.

Ob du entprellen musst, kann ich nicht sagen. Hier wurde ja schon mal vorgeschlagen RC zu verwenden, dies würde dann wahrscheinlich am Signal für Ext Interrupt ausreichen.

Dirk :ciao:
 
Scheint zu Funktionieren

Code:
/************************************************************************************************************
*								    	Drehimpulsgeber (Optisch)											*
*								   __________________________________										*
*																											*
*			    			- Auswerten eines Drehimpulsgeber´s (Drehencoder)								*
*																											*
* 																											*
*										MRL - 20 C	(ohne Taster)											*
*																											*
*											Beschreibung :													*
*				  Phase_A wird auf INT0 gelegt und INT0 wird auf "fallende Flanke"							*
*				  eingestellt. In der ISR von INT0 wird der aktuelle Status von "Phase_B"					*
				  ausgewertet! Die Drehrichtung wird in der Variable "Drehrichtung" gepeichert	*			*
************************************************************************************************************/

#define F_CPU 16000000

#define Phase_A ((PIND & (1<<PIND6))) // Phase A
#define Phase_B ((PIND & (1<<PIND4))) // Phase B

#define LINKS_AN PORTB |= (1<<PD0)
#define RECHTS_AN PORTB |= (1<<PD1)

#define LINKS_AUS PORTB &= ~(1<<PD0)
#define RECHTS_AUS PORTB &= ~(1<<PD1)

#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>

volatile uint8_t Drehrichtung;

int main(void)
{
	
	PORTD |= ((1<<PD4) | (1<<PD6)); // PullUp´s aktivieren
	DDRB  |= ((1<<PB0) | (1<<PB1)); // Ausgänge für LED´s
	
	MCUCR |= (1<<ISC01); // INT0 Sense auf fallende Flanke einstellen
	GICR  |= (1<<INT0);  // INT0 Interrupt Enable 
	
	sei();
	
    while(1)
    {
		
		switch (Drehrichtung)
		{
			case 1:
			{
				LINKS_AN;
				_delay_ms(100);
				LINKS_AUS;
				Drehrichtung = 3;
			}
				break;
			
			case 2:
			{
				RECHTS_AN;
				_delay_ms(100);
				LINKS_AUS;
				Drehrichtung = 3;
			}
				break;
			
			case 3:
			{
				LINKS_AUS;
				RECHTS_AUS;
			}
			
		} // Ende switch (Drehrichtung)
			

    } // Ende while(1)
} // Ende Main


ISR (INT0_vect)

{
	
	
	if (Phase_B)
	{
		Drehrichtung = 1;
	}

	if (Phase_A)
	{
		Drehrichtung = 2;
	}

	
}
 
Also das Signal welches am ExtInt haengt ist in der ISR immer low. Eine Abfrage ist hier unnoetig.

EDIT:

Ungünstig ist es, wenn Phase_B an ExtInt angeschlossen ist, da bei fallender Flanke die Rasterung ist. Hier solltest du dann auf steigende Flanke triggern.

Wenn Phase_A an ExtInt angeschlossen ist, könntest du es in der ISR so lösen:

Code:
if (Phase_A)
{
  Drehrichtung = 2;
} else {
  Drehrichtung = 1;
}

Das Hauptprogramm muss sich das Ergebnis allerdings schnell genug abholen. Im Moment hast du eine Menge _delay_ms() im Hauptprogramm.

Ist bei dem verwendeten Mikrocontroller tatsächlich ExtInt0 an PD4 oder PD6?

Wegen:
Code:
#define Phase_A ((PIND & (1<<PIND6))) // Phase A
#define Phase_B ((PIND & (1<<PIND4))) // Phase B
 
Also das Signal welches am ExtInt haengt ist in der ISR immer low. Eine Abfrage ist hier unnoetig.

EDIT:

Ungünstig ist es, wenn Phase_B an ExtInt angeschlossen ist, da bei fallender Flanke die Rasterung ist. Hier solltest du dann auf steigende Flanke triggern.

Wenn Phase_A an ExtInt angeschlossen ist, könntest du es in der ISR so lösen:

Code:
if (Phase_A)
{
  Drehrichtung = 2;
} else {
  Drehrichtung = 1;
}

Das Hauptprogramm muss sich das Ergebnis allerdings schnell genug abholen. Im Moment hast du eine Menge _delay_ms() im Hauptprogramm.

Ist bei dem verwendeten Mikrocontroller tatsächlich ExtInt0 an PD4 oder PD6?

Wegen:
Code:
#define Phase_A ((PIND & (1<<PIND6))) // Phase A
#define Phase_B ((PIND & (1<<PIND4))) // Phase B

Hallo Dirk,

Die _delay Zeiten waren nur zum Testen da. Da ich ja jetzt meine Phase_A am INT0 habe (MEGA32 / PD2) brauche ich diesen ja nicht als Eingang zu konfigurieren.
Bis jetzt wollte ich nur mal schauen wie sich ein solch "Drehimpulsgeber" verhält. Das mit dem Auswerten ist jetzt erstmal unkritisch. Hauptsache es funktioniert so erstmal :)

Später wenn ich meinen "Belichtungstimer" baue, wird das wohl mehr ins Gewicht fallen.
 

Über uns

  • Makerconnect ist ein Forum, welches wir ausschließlich für einen Gedankenaustausch und als Diskussionsplattform für Interessierte bereitstellen, welche sich privat, durch das Studium oder beruflich mit Mikrocontroller- und Kleinstrechnersystemen beschäftigen wollen oder müssen ;-)
  • Dirk
  • Du bist noch kein Mitglied in unserer freundlichen Community? Werde Teil von uns und registriere dich in unserem Forum.
  •  Registriere dich

User Menu

 Kaffeezeit

  • Wir arbeiten hart daran sicherzustellen, dass unser Forum permanent online und schnell erreichbar ist, unsere Forensoftware auf dem aktuellsten Stand ist und der Server regelmäßig gewartet wird. Auch die Themen Datensicherheit und Datenschutz sind uns wichtig und hier sind wir auch ständig aktiv. Alles in allem, sorgen wir uns darum, dass alles Drumherum stimmt :-)

    Dir gefällt das Forum und unsere Arbeit und du möchtest uns unterstützen? Unterstütze uns durch deine Premium-Mitgliedschaft!
    Wir freuen uns auch über eine Spende für unsere Kaffeekasse :-)
    Vielen Dank! :ciao:


     Spende uns! (Paypal)