Actions

Difference between revisions of "Reading Rotary Encoders"

From Just in Time

 
Line 4: Line 4:
  
 
The main program just loops and does nothing. The first vp communicates directly with the second.
 
The main program just loops and does nothing. The first vp communicates directly with the second.
 +
 +
;=======================================================================
 +
 +
;TITLE:        4x7segments.src
 +
;
 +
;PURPOSE:      Read pulses from a rotary encoder, adapt a counter
 +
; and output to 4 7-segment led displays
 +
;
 +
;AUTHOR:        Danny Havenith
 +
;
 +
;REVISIONS:
 +
;  <mm/dd/yy> - <details of revision>
 +
;              <more details of same revision>
 +
;
 +
;CONNECTIONS:
 +
; ra.0 and ra.1: encoder inputs
 +
; rc: led segment outputs
 +
; rb.0-4: led column outputs
 +
;
 +
;=======================================================================
 +
 +
 +
;-------------------------- DEVICE DIRECTIVES --------------------------
 +
 +
DEVICE SX28,OSC4MHZ,TURBO
 +
DEVICE STACKX, OPTIONX
 +
IRC_CAL IRC_SLOW
 +
 +
RESET Initialize
 +
 +
;------------------------------ CONSTANTS ------------------------------
 +
 +
TicksPerMs EQU 20 ; interrupts per ms
 +
CyclesPerTick EQU 200 ; cycles per interrupt
 +
 +
 +
------------------------------ VARIABLES ------------------------------
 +
ORG $10
 +
 +
BankLeds = $
 +
 +
MSTimer DS 1
 +
CurrentDigit DS 1
 +
CurrentColumn DS 1
 +
Digits DS 4
 +
 +
CounterA DS 1
 +
CounterB DS 1
 +
CounterC DS 1
 +
 +
BankEncoder = $
 +
EncoderState DS 1
 +
temp DS 1
 +
 +
 +
ColumnPort EQU rb
 +
RowPort EQU rc
 +
 +
EncoderPort EQU ra ; port for the rotary encoder
 +
EncoderMask EQU $03 ; which bits to use.
 +
 +
;---------------------------- DEBUG SETTINGS ---------------------------
 +
 +
FREQ 4_000_000
 +
 +
; WATCH <Symbol>,<bit count>,<format>
 +
 +
WKED_W equ $0A ;Write MIWU/RB Interrupt edge setup, 0 = falling, 1 = rising
 +
WKEN_W equ $0B ;Write MIWU/RB Interrupt edge setup, 0 = enabled, 1 = disabled
 +
ST_W equ $0C ;Write Port Schmitt Trigger setup, 0 = enabled, 1 = disabled
 +
LVL_W equ $0D ;Write Port Schmitt Trigger setup, 0 = enabled, 1 = disabled
 +
PLP_W equ $0E ;Write Port Schmitt Trigger setup, 0 = enabled, 1 = disabled
 +
DDIR_W equ $0F ;Write Port Direction
 +
 +
RA_latch equ %00000000 ;SX18/20/28/48/52 port A latch init
 +
RA_DDIR equ %11111111 ;see under pin definitions for port A DDIR value
 +
RA_LVL equ %00000000 ;SX18/20/28/48/52 port A LVL value
 +
RA_PLP equ %11111111 ;SX18/20/28/48/52 port A PLP value
 +
 +
RB_latch equ %00000000 ;SX18/20/28/48/52 port B latch init
 +
RB_DDIR equ %11110000 ;SX18/20/28/48/52 port B DDIR value
 +
RB_ST equ %11111111 ;SX18/20/28/48/52 port B ST value
 +
RB_LVL equ %00000000 ;SX18/20/28/48/52 port B LVL value
 +
RB_PLP equ %11111111 ;SX18/20/28/48/52 port B PLP value
 +
 +
RC_latch equ %00000000 ;SX18/20/28/48/52 port C latch init
 +
RC_DDIR equ %00000000 ;SX18/20/28/48/52 port C DDIR value
 +
RC_ST equ %11111111 ;SX18/20/28/48/52 port C ST value
 +
RC_LVL equ %00000000 ;SX18/20/28/48/52 port C LVL value
 +
RC_PLP equ %11111111 ;SX18/20/28/48/52 port C PLP value
 +
 +
;-------------------------- INTERRUPT ROUTINE --------------------------
 +
ORG $0
 +
 +
; break Interrupt
 +
Interrupt
 +
; timer
 +
bank BankLeds
 +
mov w, #TicksPerMs
 +
dec MSTimer
 +
snz
 +
mov MSTimer, w
 +
sz
 +
jmp EndInterrupt
 +
 +
mov w, #Digits
 +
add w, CurrentDigit
 +
mov fsr, w
 +
mov w, IND
 +
call Decode
 +
clr ColumnPort
 +
mov RowPort, w
 +
mov ColumnPort, CurrentColumn
 +
 +
; next column
 +
clc
 +
rr CurrentColumn ; rotate column left
 +
mov w, #%00001000
 +
inc CurrentDigit ; increase digit counter
 +
snc ; reset if digit = 4
 +
mov CurrentColumn, w
 +
snc
 +
clr CurrentDigit
 +
 +
:EndLeds
 +
 +
break ReadEncoder
 +
ReadEncoder
 +
        mov w, EncoderPort          ;get change between current and previous
 +
                            ;encoder state in w
 +
        xor w, EncoderState    ;
 +
       
 +
        xor EncoderState, w    ;update state and preserve difference in w
 +
 +
        and w, #EncoderMask        ;check if there is change
 +
        snz
 +
          jmp :EndEncoder      ;no change, read encoder again
 +
 +
        ;if both bits changed, this will be an error, but we ignore it here
 +
        ;xor w, #$03
 +
        ;skpnz
 +
        ; jmp enc_error
 +
 +
        ;calculate direction in temp.1
 +
        mov temp, w     
 +
        mov w, <<EncoderState
 +
        xor w, EncoderState
 +
        xor temp, w
 +
 +
        sb temp.1
 +
          call EncoderIncrease      ;Encoder moved up
 +
        snb temp.1
 +
          call EncoderDecrease      ;Encoder moved down
 +
 +
:EndEncoder
 +
 +
EndInterrupt
 +
mov w, #-CyclesPerTick
 +
retiw
 +
 +
EncoderIncrease
 +
inc Digits + 3
 +
cjne Digits + 3, #10, :EndInc
 +
clr Digits + 3
 +
 +
inc Digits + 2
 +
cjne Digits + 2, #10, :EndInc
 +
clr Digits + 2
 +
 +
inc Digits + 1
 +
cjne Digits + 1, #10, :EndInc
 +
clr Digits + 1
 +
 +
inc Digits
 +
cjne Digits, #10, :EndInc
 +
clr Digits
 +
:EndInc
 +
retp
 +
 +
EncoderDecrease
 +
dec Digits + 3
 +
cjne Digits + 3, #$FF, :EndDec
 +
mov Digits + 3, #09
 +
 +
dec Digits + 2
 +
cjne Digits + 2, #$FF, :EndDec
 +
mov Digits + 2, #09
 +
 +
dec Digits + 1
 +
cjne Digits + 1, #$FF, :EndDec
 +
mov Digits + 1, #09
 +
 +
dec Digits
 +
cjne Digits, #$FF, :EndDec
 +
mov Digits, #09
 +
:EndDec
 +
retp
 +
 +
Decode
 +
and w, #$0F
 +
jmp PC+w
 +
retw %00000101 ;0
 +
retw %11011101 ;1
 +
retw %10000110 ;2
 +
retw %10010100 ;3
 +
retw %01011100 ;4
 +
retw %00110100 ;5
 +
retw %00100100 ;6
 +
retw %10011101 ;7
 +
retw %00000100 ;8
 +
retw %00010100 ;9
 +
retw %00001100 ;A
 +
retw %01100100 ;b
 +
retw %00100111 ;C
 +
retw %11000100 ;d
 +
retw %00100110 ;E
 +
retw %00101110 ;F
 +
 +
;------------------------ INITIALIZATION ROUTINE -----------------------
 +
 +
Initialize
 +
; Configure all ports
 +
mov m, #ST_W ;point MODE to write ST register
 +
mov    w,#RB_ST            ;Setup RB Schmitt Trigger, 0 = enabled, 1 = disabled
 +
mov !rb,w
 +
mov    w,#RC_ST            ;Setup RC Schmitt Trigger, 0 = enabled, 1 = disabled
 +
mov !rc,w
 +
mov m, LVL_W ;point MODE to write LVL register
 +
mov    w,#RA_LVL            ;Setup RA CMOS or TTL levels, 0 = TTL, 1 = CMOS
 +
mov !ra,w
 +
mov    w,#RB_LVL            ;Setup RB CMOS or TTL levels, 0 = TTL, 1 = CMOS
 +
mov !rb,w
 +
mov    w,#RC_LVL            ;Setup RC CMOS or TTL levels, 0 = TTL, 1 = CMOS
 +
mov !rc,w
 +
 +
mov w,#RA_PLP            ;Setup RA Weak Pull-up, 0 = enabled, 1 = disabled
 +
mov !ra,w
 +
mov    w,#RB_PLP            ;Setup RB Weak Pull-up, 0 = enabled, 1 = disabled
 +
mov !rb,w
 +
mov    w,#RC_PLP            ;Setup RC Weak Pull-up, 0 = enabled, 1 = disabled
 +
mov !rc,w
 +
 +
mov m, #DDIR_W ;point MODE to write DDIR register
 +
mov w,#RA_DDIR ;Setup RA Direction register, 0 = output, 1 = input
 +
mov !ra,w
 +
mov w,#RB_DDIR ;Setup RB Direction register, 0 = output, 1 = input
 +
mov !rb,w
 +
mov w,#RC_DDIR ;Setup RC Direction register, 0 = output, 1 = input
 +
mov !rc,w
 +
 +
mov    w,#RA_latch          ;Initialize RA data latch
 +
mov    ra,w
 +
mov    w,#RB_latch        ;Initialize RB data latch
 +
mov    rb,w
 +
mov    w,#RC_latch          ;Initialize RC data latch
 +
mov    rc,w
 +
 +
; zero all ram (SX28)
 +
clr fsr ;reset all ram banks
 +
:zero_ram sb fsr.4 ;are we on low half of bank?
 +
setb fsr.3 ;If so, don't touch regs 0-7
 +
clr ind ;clear using indirect addressing
 +
incsz fsr ;repeat until done
 +
jmp :zero_ram
 +
 +
:init_leds bank BankLeds
 +
mov CurrentDigit, #0
 +
mov CurrentColumn, #1
 +
 +
;---------------------------- MAIN PROGRAM -----------------------------
 +
 +
Main
 +
 +
mov Digits, #1
 +
mov Digits + 1, #2
 +
mov Digits + 2, #3
 +
mov Digits + 3, #4
 +
mov !option, #%10011111 ;enable rtcc interrupt
 +
 +
:loop
 +
  jmp :loop
 +
 +
 +
 +
 +
 +
;----------------------------- SUBROUTINES -----------------------------
 +
 +
;<GlobalLabel>
 +
;<detailed description of routine>
 +
 +
; <inst> <op1>,<op2> ;<time> <comment>

Revision as of 14:46, 30 August 2006

The following SX assembly contains two virtual pheripherals:

  • Reading a rotary encoder
  • driving 4 7-segment led displays

The main program just loops and does nothing. The first vp communicates directly with the second.

;=======================================================================

;TITLE:         4x7segments.src
;
;PURPOSE:       Read pulses from a rotary encoder, adapt a counter
;			and output to 4 7-segment led displays
;
;AUTHOR:        Danny Havenith
;
;REVISIONS:
;  <mm/dd/yy> - <details of revision>
;               <more details of same revision>
;
;CONNECTIONS:
;	ra.0 and ra.1: encoder inputs
;	rc: led segment outputs
;	rb.0-4: led column outputs
;
;=======================================================================


;-------------------------- DEVICE DIRECTIVES --------------------------

		DEVICE		SX28,OSC4MHZ,TURBO
		DEVICE		STACKX, OPTIONX
		IRC_CAL		IRC_SLOW

		RESET		Initialize

;------------------------------ CONSTANTS ------------------------------

TicksPerMs	EQU	20	; interrupts per ms
CyclesPerTick	EQU	200	; cycles per interrupt


------------------------------ VARIABLES ------------------------------
			ORG	$10

BankLeds	= $

MSTimer		DS	1
CurrentDigit	DS	1
CurrentColumn	DS	1
Digits		DS	4

CounterA	DS	1
CounterB	DS	1
CounterC	DS	1

BankEncoder	= $
EncoderState	DS 	1
temp		DS	1


ColumnPort	EQU 	rb
RowPort		EQU	rc

EncoderPort	EQU	ra 	; port for the rotary encoder
EncoderMask	EQU	$03	; which bits to use.

;---------------------------- DEBUG SETTINGS ---------------------------

		FREQ	4_000_000
	
;		WATCH	<Symbol>,<bit count>,<format>

WKED_W		equ	$0A		;Write MIWU/RB Interrupt edge setup, 0 = falling, 1 = rising
WKEN_W		equ	$0B		;Write MIWU/RB Interrupt edge setup, 0 = enabled, 1 = disabled
ST_W		equ	$0C		;Write Port Schmitt Trigger setup, 0 = enabled, 1 = disabled
LVL_W		equ	$0D		;Write Port Schmitt Trigger setup, 0 = enabled, 1 = disabled
PLP_W		equ	$0E		;Write Port Schmitt Trigger setup, 0 = enabled, 1 = disabled
DDIR_W		equ	$0F		;Write Port Direction

RA_latch	equ	%00000000		;SX18/20/28/48/52 port A latch init
RA_DDIR		equ	%11111111		;see under pin definitions for port A DDIR value
RA_LVL		equ	%00000000		;SX18/20/28/48/52 port A LVL value
RA_PLP		equ	%11111111		;SX18/20/28/48/52 port A PLP value

RB_latch	equ	%00000000		;SX18/20/28/48/52 port B latch init
RB_DDIR		equ	%11110000		;SX18/20/28/48/52 port B DDIR value
RB_ST		equ	%11111111		;SX18/20/28/48/52 port B ST value
RB_LVL		equ	%00000000		;SX18/20/28/48/52 port B LVL value
RB_PLP		equ	%11111111		;SX18/20/28/48/52 port B PLP value

RC_latch	equ	%00000000		;SX18/20/28/48/52 port C latch init
RC_DDIR		equ	%00000000		;SX18/20/28/48/52 port C DDIR value
RC_ST		equ	%11111111		;SX18/20/28/48/52 port C ST value
RC_LVL		equ	%00000000		;SX18/20/28/48/52 port C LVL value
RC_PLP		equ	%11111111		;SX18/20/28/48/52 port C PLP value

;-------------------------- INTERRUPT ROUTINE --------------------------
		ORG	$0
		
;	break Interrupt
Interrupt
; timer
	bank BankLeds
	mov w, #TicksPerMs
	dec MSTimer
	snz
	mov MSTimer, w
	sz
	jmp EndInterrupt

	mov w, #Digits
	add w, CurrentDigit
	mov fsr, w
	mov w, IND
	call Decode
	clr ColumnPort
	mov RowPort, w
	mov ColumnPort, CurrentColumn

	; next column
	clc
	rr CurrentColumn	; rotate column left
	mov w, #%00001000
	inc CurrentDigit		; increase digit counter
	snc 		; reset if digit = 4
	mov CurrentColumn, w
	snc 
	clr CurrentDigit

:EndLeds

	break ReadEncoder
ReadEncoder
        mov w, EncoderPort           ;get change between current and previous 
                            ;encoder state in w
        xor w, EncoderState    ;
        
        xor EncoderState, w    ;update state and preserve difference in w

        and w, #EncoderMask         ;check if there is change
        snz
         jmp :EndEncoder       ;no change, read encoder again

        ;if both bits changed, this will be an error, but we ignore it here
        ;xor w, #$03
        ;skpnz
        ; jmp enc_error

        ;calculate direction in temp.1
        mov temp, w       
        mov w, <<EncoderState
        xor w, EncoderState
        xor temp, w

        sb temp.1
         call EncoderIncrease       ;Encoder moved up
        snb temp.1
         call EncoderDecrease       ;Encoder moved down

:EndEncoder

EndInterrupt
	mov w, #-CyclesPerTick		
	retiw

EncoderIncrease
	inc	Digits + 3
	cjne	Digits + 3, #10, :EndInc
	clr 	Digits + 3

	inc	Digits + 2
	cjne	Digits + 2, #10, :EndInc
	clr 	Digits + 2

	inc	Digits + 1
	cjne	Digits + 1, #10, :EndInc
	clr 	Digits + 1

	inc	Digits 
	cjne	Digits, #10, :EndInc
	clr 	Digits
:EndInc
	retp

EncoderDecrease
	dec	Digits + 3
	cjne	Digits + 3, #$FF, :EndDec
	mov	Digits + 3, #09

	dec	Digits + 2
	cjne	Digits + 2, #$FF, :EndDec
	mov	Digits + 2, #09

	dec	Digits + 1
	cjne	Digits + 1, #$FF, :EndDec
	mov	Digits + 1, #09

	dec	Digits
	cjne	Digits, #$FF, :EndDec
	mov	Digits, #09
:EndDec		
	retp

Decode
	and w, #$0F
	jmp PC+w
	retw %00000101 ;0
	retw %11011101 ;1
	retw %10000110 ;2
	retw %10010100 ;3
	retw %01011100 ;4
	retw %00110100 ;5
	retw %00100100 ;6
	retw %10011101 ;7
	retw %00000100 ;8
	retw %00010100 ;9
	retw %00001100 ;A
	retw %01100100 ;b
	retw %00100111 ;C
	retw %11000100 ;d
	retw %00100110 ;E
	retw %00101110 ;F

;------------------------ INITIALIZATION ROUTINE -----------------------

Initialize
		; Configure all ports
		mov 	m, #ST_W			;point MODE to write ST register
		mov     w,#RB_ST            	;Setup RB Schmitt Trigger, 0 = enabled, 1 = disabled
		mov	!rb,w		
		mov     w,#RC_ST            	;Setup RC Schmitt Trigger, 0 = enabled, 1 = disabled
		mov	!rc,w	
		mov 	m, LVL_W			;point MODE to write LVL register
		mov     w,#RA_LVL            	;Setup RA CMOS or TTL levels, 0 = TTL, 1 = CMOS
		mov	!ra,w		 
		mov     w,#RB_LVL            	;Setup RB CMOS or TTL levels, 0 = TTL, 1 = CMOS
		mov	!rb,w		
		mov     w,#RC_LVL            	;Setup RC CMOS or TTL levels, 0 = TTL, 1 = CMOS
		mov	!rc,w	

		mov 	w,#RA_PLP            	;Setup RA Weak Pull-up, 0 = enabled, 1 = disabled
		mov	!ra,w		 
		mov     w,#RB_PLP            	;Setup RB Weak Pull-up, 0 = enabled, 1 = disabled
		mov	!rb,w		
		mov     w,#RC_PLP            	;Setup RC Weak Pull-up, 0 = enabled, 1 = disabled
		mov	!rc,w	

		mov 	m, #DDIR_W			;point MODE to write DDIR register
		mov	w,#RA_DDIR		;Setup RA Direction register, 0 = output, 1 = input		
		mov	!ra,w	
		mov	w,#RB_DDIR		;Setup RB Direction register, 0 = output, 1 = input
		mov	!rb,w			
		mov	w,#RC_DDIR		;Setup RC Direction register, 0 = output, 1 = input
		mov	!rc,w			

		mov     w,#RA_latch          	;Initialize RA data latch
		mov     ra,w		
		mov     w,#RB_latch         	;Initialize RB data latch
		mov     rb,w		
		mov     w,#RC_latch          	;Initialize RC data latch
		mov     rc,w		

; zero all ram (SX28)
		clr	fsr			;reset all ram banks
:zero_ram	sb	fsr.4			;are we on low half of bank?
		setb	fsr.3			;If so, don't touch regs 0-7
		clr	ind			;clear using indirect addressing
		incsz	fsr			;repeat until done
		jmp	:zero_ram

:init_leds	bank BankLeds
		mov CurrentDigit, #0
		mov CurrentColumn, #1

;---------------------------- MAIN PROGRAM -----------------------------

Main

	mov Digits, #1
	mov Digits + 1, #2
	mov Digits + 2, #3
	mov Digits + 3, #4
	mov	!option, #%10011111	;enable rtcc interrupt

:loop	
 	jmp :loop




	
;----------------------------- SUBROUTINES -----------------------------

;<GlobalLabel>
;<detailed description of routine>

;		<inst>	<op1>,<op2>		;