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> ;