Rotationssensor

Övriga diskussioner relaterade till komponenter. Exempelvis radiorör, A/D, kontaktdon eller sensorer.
Användarvisningsbild
Icecap
Inlägg: 26632
Blev medlem: 10 januari 2005, 14:52:15
Ort: Starup (Haderslev), Danmark

Inlägg av Icecap »

Annars kan man koppla t.ex. A till en interrupt-pinne och sen vid interrupt kolla läget på B för att besluta upp- eller ner-räkning.
Användarvisningsbild
JimmyAndersson
Inlägg: 26568
Blev medlem: 6 augusti 2005, 21:23:33
Ort: Oskarshamn (En bit utanför)
Kontakt:

Inlägg av JimmyAndersson »

Såg att min D-flipflop (74LS374N) saknade separata CKL och CLR-pinnar så lösningen med flipflop sprack. Ska testa Icecap's lösning istället. Den ser mycket smidig och enkelt ut.

Eftersom alla mina "vanliga" interruptpinnar är upptagna så måste jag använda de som ger "interrupt on change". Men då ger B bara 1, 0, 1, 0 (vid interrupt på A) oavsett vilket håll man snurrar. Men om jag läser av både A och B så verkar det fungera fint.

Vrider åt ena hållet:
AB
00 = 0 <-- Ett hack (eller "Dentent stability point".)
10 = 2 <-- Ger interrupt
11 = 3 <-- Nästa hack
01 = 1 <-- Ger interrupt
00 = 0 <-- Hack igen
10 = 2 <-- Ger interrupt
osv..

Andra hållet:
AB
00 = 0 <-- Hack. Ger interrupt
01 = 1
11 = 3 <-- Nästa hack. Ger interrupt
10 = 2
00 = 0 <-- Hack igen. Ger interrupt
01 = 1

När det blir interrupt ser det alltså ut såhär:
Ena hållet: 1, 2, 1, 2. Andra hållet: 0, 3, 0, 3.

Nu ska jag bara knappa lite kod och se hur det fungerar i praktiken. :)
sodjan
EF Sponsor
Inlägg: 43247
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Inlägg av sodjan »

Gjorde en rutin för att läsa av en rot.sensor till en PIC18 för något
år seden. Det var typen som man kan trycka på, men det är ganska
ointressant, det är ju bara en kontakt som lika gärna (utifrån PIC'ens
horizont) kunde vara vilken switch som helst.

Hur som helst, med ett timerinterrupt läste jag av den ca 400 gånger/sek.
Sedan var det bara att jämföra det gamla och nya statuset och avgöra
vilken riktinng den hade vridit sig. Att den ibland (mest om man vred lite
snabbare) missade eller fick ett steg i fel riktning spelar ingen som helst roll,
i praktiskt bruk är det inget som märks. När man vred sakta missade den inte.

Jag hade och en accellerationsfunktion i den, om man vred snabbare
än en viss hastiget, så räknade programvaran dubbla eller tredubbla
"klick" för varje steg. Praktiskt.

Fördelen med pollning i detta fall, är att det blir små problem med
kontaktstudsar, om man kör interruptlösninge så *kan* man få en
del problem med det, det beror lite på kvaliteten på sensorn och
eventuell filtrering av signalerna med RC länkar.
Användarvisningsbild
Chribbe76
EF Sponsor
Inlägg: 1167
Blev medlem: 17 januari 2004, 22:43:17
Ort: Stockholm

Inlägg av Chribbe76 »

Jag föredrar oxå pollning för att läsa quadrature.

Posta din rutin sodjan.
sodjan
EF Sponsor
Inlägg: 43247
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Inlägg av sodjan »

Nja, det är flera olika ASM filer, och uppbyggt med Olin Lathrop's
ASM-utvecklingsmiljö för PIC, så om man inte är van att jobba
i den så kan det vara lite tuft att läsa...

Om någon är intresserad av Olin's miljö, så har jag ställt samman
en PDF beskrivning som finns här : http://www.jescab.se/embedinc.htm
Notera att dokumentet är några år gammal och Olin har uppdaterat
en hel del, bl.a med dsPIC support.

Olin's kit finns här : http://www.embedinc.com/pic/
för den som är intresserad...

Olin själv syns här : http://www.embedinc.com/manage.asp :-)
idiotdea
Inlägg: 471
Blev medlem: 26 juli 2006, 16:11:34
Ort: Vasa, Finland
Kontakt:

Inlägg av idiotdea »

Eftersom jag bara för några dagar sedan skrev en rutin för att läsa av rotationssensorer i assembler så kan jag ju posta den här, kanske den hjälper (eller stjälper? :? ) någon. Hur som helst är den snabbt testad och den fungerar någorlunda bra för mig. Det finns några småsaker som borde fixas ännu förrän allt är perfekt, men som sagt, det fungerar.

Själv använder jag PORTB interrupten för att avläsa rotationssensorn, men rutinen i sig ger blanka f*n i hur den matas med data. :)

Jag förklarar inte koden speciellt här, eftersom jag när jag skrev den försökte få till hyfsade kommentarer i koden (på engelska).

Kod: Markera allt

cblock		H'20'
	ROT_TMP		; Temporary byte for rotary encoder functions
	ROT_INPUT	; Input of rotary encoder passed to ParseRotaryEncoder
	ROT_STATE	; State of the rotary encoder, both passed and returned
	ROT_VAL		; Value to be incremented or decremented each "complete
			; turn" or the encoder. CW increments, CCW decrements.
endc

; *** ParseRotaryEncoder ***************************************************** ;
; ParseRotaryEncoder will compare input from ROT_INPUT and ROT_STATE, to see
; wheter the rotary encoder has moved in any (valid) direction since the last
; reading. It will update ROT_STATE to reflect the new state unless the input is
; the same as before.
;
; Explanation of bits ROT_INPUT and ROT_STATE
; ROT_INPUT: Contains nothing but 2 bit input of encoder in bits <0:1>. Period.
; ROT_STATE: Bits <0:1> contains old input of encoder (as compared to new in
;	     ROT_INPUT <0:1>. Bits<6:7> contains the moving direction of the
;	     encoder, where bit<6>=0 means CW and bit<6>=1 means CCW. Bit<7> is
;	     set if we are moving in any direction (usually ROT_INPUT != 0).
; **************************************************************************** ;
ParseRotaryEncoder:
	; Test if new input is the same as old one, and if it is, return without
	; doing anything else.
	movf	ROT_STATE, W
	andlw	H'3'
	subwf	ROT_INPUT, W
	btfsc	STATUS, Z
	return				; Same input, return
	
	; Calculate the moving direction, and at the same time we check
	; wheter the "direction" is valid. We do this by putting the old input
	; in W<2:3> and new input in W<0:1> and calling a lookup table.
	movf	ROT_STATE, W
	andlw	H'3'
	movwf	ROT_TMP
	bcf	STATUS, C		; Don't shift in unwanted carry flag
	rlf	ROT_TMP, F
	rlf	ROT_TMP, W
	iorwf	ROT_INPUT, W
	call	_ParseRotaryEncoder_DirectionTable
	xorlw	H'1'			; Change the direction since we did
					; the lookup in "reverse" order
					
	; Check wheter the moving direction is valid (make sure we didn't miss
	; any inputs in between readings).
	movwf	ROT_TMP
	btfss	ROT_TMP, 1		; Bit 1 will be set if rotation is valid
	goto	_ParseRotaryEncoder_ResetAndEnd
	
	; Make sure we are moving in the same direction as before (just compare
	; ROT_STATE<6:7> with newly returned direction).
	bcf	STATUS, C
	rlf	ROT_TMP, F
	rlf	ROT_TMP, F
	swapf	ROT_STATE, W
	andlw	H'C'
	subwf	ROT_TMP, W
	btfss	STATUS, Z
	goto	_ParseRotaryEncoder_TestFirstMove	; Direction not same...
	call	_ParseRotaryEncoder_SaveNewInput	; Same direction
	
	; Test if new input is 00, which marks a "complete turn". Increment/
	; decrement ROT_VAL every turn. Direction is determined by checking
	; ROT_STATE<6>
	movf	ROT_INPUT, F
	btfss	STATUS, Z
	return				; Still not a complete turn; return.
	btfss	ROT_STATE, 6
	incf	ROT_VAL			; CW direction, inc
	btfsc	ROT_STATE, 6
	decf	ROT_VAL			; CCW direction, dec
	goto	_ParseRotaryEncoder_ResetAndEnd
	
; === _ParseRotaryEncoder_SaveNewInput ======================================= ;
; Save new input from ROT_INPUT to ROT_STATE
; ============================================================================ ;
_ParseRotaryEncoder_SaveNewInput:	
	movlw	H'FC'
	andwf	ROT_STATE
	movf	ROT_INPUT, W
	iorwf	ROT_STATE, F
	return
	
; === _ParseRotaryEncoder_TestFirstMove ====================================== ;
; Test if ROT_STATE is uninitialized. If is is the movement is valid and we
; update it to reflect the new data. Otherwise reset ROT_STATE and return.
; ============================================================================ ;
_ParseRotaryEncoder_TestFirstMove:
	movf	ROT_STATE, W
	andlw	H'C0'
	btfss	STATUS, Z
	goto	_ParseRotaryEncoder_ResetAndEnd
	; Save direction
	swapf	ROT_TMP, F
	movlw	H'3F'
	andwf	ROT_STATE, F
	movf	ROT_TMP, W
	iorwf	ROT_STATE, F
	call	_ParseRotaryEncoder_SaveNewInput	; Save input
	goto	_PortBInterrupt_End
	
; === _ParseRotaryEncoder_ResetAndEnd ======================================== ;
; Reset ROT_STATE and return
; ============================================================================ ;
_ParseRotaryEncoder_ResetAndEnd:
	movlw	H'0'
	movwf	ROT_STATE
	return

; === _ParseRotaryEncoder_DirectionTable ===================================== ;
; W should contain old direction in bits<2:3> and new direction in bits<0:1>.
; We then return a value through W describing the direction, where 00 means no
; change or moving too fast. 01 and 11 for CW and CCW direction, respectively.
; ============================================================================ ;
_ParseRotaryEncoder_DirectionTable:
	addwf	PCL, 1
	retlw	B'00'		; 00 => 00, no change
	retlw	B'10'		; 00 => 01, CW
	retlw	B'11'		; 00 => 10, CCW
	retlw	B'00'		; 00 => 11, moving too fast
	retlw	B'11'		; 01 => 00, CCW
	retlw	B'00'		; 01 => 01, no change
	retlw	B'00'		; 01 => 10, moving too fast
	retlw	B'10'		; 01 => 11, CW
	retlw	B'10'		; 10 => 00, CW
	retlw	B'00'		; 10 => 01, moving too fast
	retlw	B'00'		; 10 => 10, no change
	retlw	B'11'		; 10 => 11, CCW
	retlw	B'00'		; 11 => 00, moving too fast
	retlw	B'11'		; 11 => 01, CCW
	retlw	B'10'		; 11 => 10, CW
	retlw	B'00'		; 11 => 11, no change
P.S. Om inlägget blev för långt kan jag lägga upp koden på mitt webbutrymme istället.
sodjan
EF Sponsor
Inlägg: 43247
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Inlägg av sodjan »

Snyggt, välskrivet, bra kommenterat, bra namn på variabler/register och labels.
Antagligen fungerar det också... :-)

Det enda jag saknar är det är skrivet som ett relokerbart CODE block
och UDATA istället för CBLOCK... :-)
Men det är enkelt att fixa för den som vill använda koden...
Virror
Inlägg: 1025
Blev medlem: 28 april 2004, 11:03:14
Ort: Göteborg
Kontakt:

Inlägg av Virror »

Har också koden till en rotationssensor styrd via interupt, men den är till AVR, har för mig att jag har både C-kod och ASM-kod.

Och ska man ha en till ett menysystem bör man ju ha en med inbyggd tryckknapp, bli ju så mycket snyggara då :)
Användarvisningsbild
JimmyAndersson
Inlägg: 26568
Blev medlem: 6 augusti 2005, 21:23:33
Ort: Oskarshamn (En bit utanför)
Kontakt:

Inlägg av JimmyAndersson »

Skulle gärna vilja se lite C-kod med interrupt, trots att det är till AVR. :)
Användarvisningsbild
Forsgren
EF Sponsor
Inlägg: 1227
Blev medlem: 24 oktober 2003, 13:45:48
Ort: Orsa

Inlägg av Forsgren »

Vart tog C-koden vägen? ;)
Vore intressant att se, har lite problem med att få det att fungera riktigt bra.
JBV
Inlägg: 411
Blev medlem: 4 maj 2006, 11:44:28
Ort: Älvsbyn

Inlägg av JBV »

Min C kod för quadrature avläsning via interrupt på AVR:

Kod: Markera allt

ISR(INT0_vect) //Channel A
{
  if(bit_is_set(PIND, PD2)) //Rising edge
  {
    if(bit_is_set(PIND, PD3)) //If B is high decrement
	{
	  ProcessVariable--;
	} else { //Else increment
	  ProcessVariable++;
	}
  } else { //Falling edge
    if(bit_is_set(PIND, PD3)) //If B is high increment
	{
	  ProcessVariable++;
	} else { //Else decrement
	  ProcessVariable--;
	}
  }
}

ISR(INT1_vect) //Channel B
{
  if(bit_is_set(PIND, PD3)) //Rising edge
  {
    if(bit_is_set(PIND, PD2)) //If A is high increment
	{
	  ProcessVariable++;
	} else { //Else decrement
	  ProcessVariable--;
	}
  } else { //Falling edge
    if(bit_is_set(PIND, PD2)) //If A is high decrement
	{
	  ProcessVariable--;
	} else { //Else increment
	  ProcessVariable++;
	}
  }
}
Hoppas den är användbar!
Användarvisningsbild
Andax
Inlägg: 4379
Blev medlem: 4 juli 2005, 23:27:38
Ort: Jönköping

Inlägg av Andax »

Som en del kanske vet har jag lagt till en enkoder för positionsåtermatning för vagnen på min inverterade pendel (har inte lagt upp de senaste bilderna eller resultaten än i tråden. Det kommer :wink: ).

Eftersom jag där körde med en mekanisk enkoder ville jag minimera risken för kontaktstudsar och körde precis som Sodjan med pollad avläsning med tillägget att jag hade räknare som räknade hur många ggr i rad som A och B varit hög resp låg. (4 räknare, dvs ggr A=0, A=1, B=0, B=1). Sen hade jag bara en tröskel på hur många gånger i rad en avläsning behövde vara stabil för att jag skulle lita på den i min upp/ner-räknare.
Den lösningen gav en bra flexibilitet eftersom man kan 'träjda' robusthet mot kontaktstudsar mot maximal rotationshastighet.
Gjort i AVR asm. Kan posta den senare när jag städat det lite om någon är intresserad...
Användarvisningsbild
BEEP
EF Sponsor
Inlägg: 1593
Blev medlem: 21 januari 2006, 16:57:56
Ort: Mölndal

Inlägg av BEEP »

Hehe... några få interrupts och så går AVR/PIC på knäna.

Det där löser man lätt i en Propeller för det är bara att lägga till Quadrature Encoder.spin så kan man ha helt gäng med encodrar :)
sodjan
EF Sponsor
Inlägg: 43247
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Inlägg av sodjan »

> Hehe... några få interrupts och så går AVR/PIC på knäna.

Det vore intressant att höra i vilket sammahang du har upplevt det.
Eller i vilken tråd du har läst det.
Skriv svar