Incremental encoders help

MaxHeadRoom

Joined Jul 18, 2013
28,699
I am a hobbyist and I wanted to use encoder in a project so just checking it

so I don't have the option to check it manually so I think I have to test it c program
If you have obtained this new or otherwise unused, why do you need to check it?
Checking an encoder of that resolution you are going to be hard pressed to see individual pulses, you should see a fluctuating voltage however, most modern VOM's are very slow reacting.
What do you intend using it on or inputting it to?
Max.
 
Last edited:

MisterBill2

Joined Jan 23, 2018
18,586
If you have obtained this new or otherwise unused, why do you need to check it?
Checking an encoder of that resolution you are going to be hard pressed to see individual pulses, you should see a fluctuating voltage however, most modern VOM's are very slow reacting.
What do you intend using it on or inputting it to?
Max.
While it is indeed very difficult to see individual pulses it is usually possible to observe the movement between both voltages, indicating thet the encoder is functional. That was the question originally posted. A complete analysis of an encoder is different from a working/not working check.
 

Thread Starter

daljeet795

Joined Jul 2, 2018
295
The multimeter test that I described will verify the functionality of the encoder, but not the accuracy. And it does work.
I think encoder is working I have tested it multimeter as well as led. When I move shaft slowly signal goes from 24 V to 0V

I need to interface the encoder to a PIC and c language. I am not necessarily looking for specific code, just thoughts, and ideas
 

MisterBill2

Joined Jan 23, 2018
18,586
I think encoder is working I have tested it multimeter as well as led. When I move shaft slowly signal goes from 24 V to 0V

I need to interface the encoder to a PIC and c language. I am not necessarily looking for specific code, just thoughts, and ideas
Interfacing to a processor can be complex if you need to get direction information and the encoder is spinning rapidly. I have done it in hardware but I did not do "C" coding and so have not a lot to offer there except that the processor mus be fast enough to keep up with the encoder output changes at the speed it is running. That used to be an issue with such high resolution encoders and the processors at the time. But it still means that you need fast code.
 

Thread Starter

daljeet795

Joined Jul 2, 2018
295
Interfacing to a processor can be complex if you need to get direction information and the encoder is spinning rapidly. I have done it in hardware but I did not do "C" coding ..
I need to get a position to reject object

It's okay if you share the logic to interface with microcontroller

Which language do you know?
 

MisterBill2

Joined Jan 23, 2018
18,586
I need to get a position to reject object

It's okay if you share the logic to interface with microcontroller

Which language do you know?
The last programming languages that I have used were for PLCs, Allen Bradley and then one of the Automation direct brands of small PLC packages. Prior to that it was "TBOSS" and "UVBOSS", which were compiled languages for electrical testers using the 6809 processors. I was quite good with them, but they are now dead languages. After that I was the one who wrote the detailed descriptions of what a program had to do, and some programmer created the code. That worked better because then there was a very detailed description of what the code was supposed to be doing every step of the way, and that made project startups run much faster.
And it was not that I was a "C" expert, just that I was able to recognize symptoms of some problems very well.
 

Thread Starter

daljeet795

Joined Jul 2, 2018
295
The last programming languages that I have used were for PLCs, Allen Bradley and then one of the Automation direct brands of small PLC packages. .
I have one delta PLC but haven't worked on it yet and i have wpl software for ladder logic

I have knowledge on microcontroler and c and little bit python
 
Last edited:

LesJones

Joined Jan 8, 2017
4,191
Several years ago I built a unit that displays the output of a quadrature encoder using a PIC16F690 and a 16 x 2 line LCD display. It displays the count in decimal on the top line and in hexadecimal on the bottom line. This is the schematic.
PIC16F690 Quad counter.png

The A and B inputs need to be a square wave between 0 and +5 volts.
The code is in assembler but you may be able to use the comments to write it in "C"
This is the source code
Code:
; Display raw count as + or - decimal number.
; Counter 5_F690  (Started 03/02/12)  Developed from Counter 5_F628b_OP
;
; There is a known problem using interrupt on change on the PIC12 and PIC16 series when a read or write to the port
; can cause the interrupt on change not to occur. Using the PIC16F628A requires the use of PORTB to drive the LCD as
; well being used for the quadrature signal inputs.
; Using the PIC16F690 allows  PORTB to be used only for the quadrature inputs.

;10/01/10 Start of modifications to give an output in 2 * 24 bit format (Chinese scale format.)
; Will use RA3 (Pin 2) & RA4 (Pin 3) for outputs.

;  Quadrature encoder Counter
;
; using LCD  (4 Bit data mode)

;       OUTPUT ROUTINE INFORMATION & Equates
; Three timer periods are required to generate the Chinese scale output.
; The periods are timed with timer1 which is set to run at the internal clock
; rate of Fosc/4 or 5MHz which is equal to a 200ns period.

; The time between number outputs is 20ms.  In timer1 ticks, this is calculated
; as 20ms / 200ns = 100,000.  Since timer1 is only  a 16 bit counter, this time
; is divided into two 10ms time intervals or 50,000 (0xc350) timer1 ticks each.
; Instruction overhead for the delay function call is ignored.
DELAY_10MS_L  equ  0x50
DELAY_10MS_H  equ  0xc3

; The time between the two numbers is 110us and the time before and after the
; number output is 55us.  The number of timer1 ticks is calculated as
; 55us / 200ns = 275.  Subtracting the delay function call overhead
; leaves 250 (0xfa) timer1 ticks.
DELAY_55US  equ  0xfa

; The clock period for the Chinese scale output is 13.2us.  The half period
; between transitions is 6.6us.  The number of timer1 ticks is calculated as
; 6.6us / 200ns = 33.  Subtracting the delay function call overhead
; leaves 10 (0x0a) timer1 ticks.
DELAY_6_6US  equ  0x0a


;I/O Ports

;   RA0
;   RA1
;   RA2   LCD RS
;   RA3   Clock_out
;   RA4   Data_out




;   RC0   LCD Data bit 4
;   RC1   LCD Data bit 5
;   RC2   LCD Data bit 6
;   RC3   LCD Data bit 7
;   RC4   LCD Not E
;   RC5   LCD RW
;   RC6   LCD RS
;   RC7   Not used

;   RB4   A_Pulse     (Quadrature encoder outputs)
;   RB5   Serial RX   Not yet used
;   RB6   B_Pulse
;   RB7   Serial TX   Not yet used

;A_IN  equ  4
;B_IN  equ  6

#define   Clock_out   PORTA,0
#define   Data_out   PORTA,1

#define   LCD_Port   PORTC
#define LCD_Tris   TRISC
#define LCD_E     PORTC,4
#define LCD_RW     PORTC,5
#define LCD_RS     PORTC,6

#Define   A_IN   4     ;Bit position for quadrature A bit
#Define   B_IN   6     ;Bit position for quadrature B bit


;PIC16F690, WDT OFF, POR ON, INTERNAL 4MHz CLOCK

   list P=16F690
   #include p16f690.inc
   __config _HS_OSC & _WDT_OFF & _PWRTE_ON

; Define variables at memory locations

EEPROM1     equ   H'00'   ; update rate
; RAM

ESEVN     equ   H'2C'   ; 10 000,000 (digit 8)
ESIX     equ   H'2D'   ; 1000,000s (digit 7 )
EFIVE     equ   H'2E'   ; 100,000s digit 6 store
EFOUR     equ   H'2F'   ; 10,000s digit 5 store
ETHREE     equ   H'30'   ; 1000s digit 4 store (kHz)
ETWO     equ   H'31'   ; 100s digit 3 store
EONE     equ   H'32'   ; 10s digit 2 store
EZERO     equ   H'33'   ; 1's digit 1 store (Hz)

REG_C     equ   H'34'   ; frequency counter LS byte  These 3 locations are called counter in Quadrature input
REG_B     equ   H'35'   ; frequency counter        program
REG_A     equ   H'36'   ; frequency counter MS byte

D_STO     equ   H'37'   ; data store
;
;
;
STORE1     equ   H'38'   ; temporary storage
STORE2     equ   H'39'   ; temporary storage
;
;
;
;
COUNT     equ   H'3A'   ;

BCD1     equ   H'3B'   ; overrange
BCD2     equ   H'3C'   ; MS decimal value
BCD3     equ   H'3D'   ;
BCD4     equ   H'3E'   ; decimal value
BCD5     equ   H'3F'   ; ls decimal value
   
BIN1     equ   H'40'   ; LS binary value
BIN2     equ   H'41'   ;
BIN3     equ   H'42'   ;
BIN4     equ   H'43'   ; MS binary value

TEMP     equ   H'44'   ; data storage
;
;
FLAG_S     equ   H'47'   ; await signal flag
TIME_I     equ   H'48'   ; initial timer


w_temp     equ  0x50    ; store W during an interrupt
status_temp     equ  0x51    ; store STATUS during an interrupt
fsr_temp     equ  0x52   ; store FSR during an interrupt

param1     equ  0x53    ; Used in dealy routines
param2  equ  0x54   ; Used in delay routines
temp1  equ  0x55   ; temporary scratch variable
temp2  equ  0x56   ; temporary scratch variable
temp3  equ  0x57   ; temporary scratch variable
   
counter     equ  0x58   ; 24 bit quadrature counter  (Use top bit as a sign bit)
sum  equ  0x5B   ; sum of products for filter
last_sum  equ  0x5C   ; last sum of products value
;
bits  equ  0x60   ; bit iterator
bytes  equ  0x61   ; byte iterator
words  equ  0x62   ; word iterator
sample_1  equ  0x63   ; first sample
sample_2  equ  0x64   ; second sample
sample_3  equ  0x65   ; third sample
;
Out_Data_0   equ   0x66   ;High byte of 24 bit word to be output
Out_Data_1   equ   0x67   ;Mid byte of 24 bit word to be output
Out_Data_2   equ   0x68   ;Low byte of 24 bit word to be output
;
frames     equ   0x69   ;Frame counter
;
tmpData     equ   0x6A   ;Used in output_hexbyte routine.

   


; start at memory 0

   org   0
   Goto MAIN

;     ********************  Start of interrupt handler  **********************

  org  0x004  ; processor interrupt vector



;   bsf   PORTA,3       ;!!!! This is for testing the time in the interrupt routine

  movwf  w_temp  ; copy W to temp register
  swapf  STATUS,W  ; swap status to be saved into W
  bcf  STATUS,RP0  ; bank 0
  movwf  status_temp  ; save status
  movf  FSR,W  ; copy FSR to temp register
  movwf  fsr_temp


capture:
  movf  PORTB,W  ; capture PORTB values
  movwf  sample_1  ; save sample 1
  movf  PORTB,W  ; capture PORTB values
  movwf  sample_2  ; save sample 2
  movf  PORTB,W  ; capture PORTB values
  movwf  sample_3  ; save sample 3

  andwf  sample_2,W  ; product term (samples 2 AND 3)
  movwf  sum  ; save it as the sum

  movf  sample_3,W  ; product term (samples 1 AND 3)
  andwf  sample_1,W  ;
  iorwf  sum,f  ; OR it to the sum

  movf  sample_2,W  ; product term (samples 1 AND 2)
  andwf  sample_1,W  ;
  iorwf  sum,f  ; OR it to the sum

  movf  sum,W  ; XOR the last and the current sums
  xorwf  last_sum,F  ;

  btfss  last_sum,A_IN  ; if the A input has not changed then
  goto  check_b  ; check if B changed
  btfsc  last_sum,B_IN  ; if the B input has changed too then
  goto  exit_isr  ; exit

check_a:
  btfsc  sum,A_IN  ; if the A input is high then
  goto  rising_a  ; this is a rising edge

falling_a:  ; else it is a falling edge
  btfsc  sum,B_IN  ; if the B input is high then
  goto  inc_counter  ; increment the counter
  goto  dec_counter  ; else decrement the counter

rising_a:
  btfss  sum,B_IN  ; if the B input is low then
  goto  inc_counter  ; increment the counter
  goto  dec_counter  ; else decrement the counter

check_b:
  btfss  last_sum,B_IN  ; if the B input has not changed then
  goto  exit_isr  ; exit
  btfsc  sum,B_IN  ; if the B input is high then
  goto  rising_b  ; this is a rising edge

falling_b:  ; else it is a falling edge
  btfss  sum,A_IN  ; if the A input is low then
  goto  inc_counter  ; increment the counter
  goto  dec_counter  ; else decrement the counter

rising_b:
  btfsc  sum,A_IN  ; if the A input is high then
  goto  inc_counter  ; increment the counter
  ; else decrement the counter

dec_counter:
   bsf   FLAG_S,0     ;Count update flag
  movlw  counter  ; move the counter address into W
  call  dec24  ; decrement the counter
  goto  exit_isr
   
inc_counter:
   bsf   FLAG_S,0     ;Count update flag
  movlw  counter  ; move the counter address into W
  call  inc24  ; increment the counter
   
exit_isr:
  movf  sum,W  ; save the current sum as the
  movwf  last_sum  ; last
   
  bcf  INTCON,RABIF  ; clear interrupt-on-change flag
   
  movf  fsr_temp,W  ; restore FSR from temp register
  movwf  FSR
  swapf  status_temp,W  ; swap STATUS_TEMP register into W
  movwf  STATUS  ; move W into STATUS register
  swapf  w_temp,F  ; swap w_temp
  swapf  w_temp,W  ; swap w_temp into W

   bcf   PORTA,3       ;!!!! This is for testing the time in the interrupt routine

  retfie  ; return from the interrupt

   
; Subroutines used by interupt handler
;*******************************************************************************
; Function:  inc24
; Description: Increment a little-endian 24 bit number.  Performance between
;  4 and 10 cycles depending on rollovers.
; Parameters:  W - pointer to the 24 bit number
; Returns:  None
;*******************************************************************************
inc24:  
  movwf  FSR  ; increment the byte pointed to
  incfsz  INDF,F  ; by the indirect register
  return  ; return if there is no byte rollover

  incfsz  FSR,F  ; increment the indirect register
  incfsz  INDF,F  ; increment the byte it points to
  return  ; return if there is no byte rollover

  incfsz  FSR,F  ; increment the indirect register
  incf  INDF,F  ; increment the byte it points to
  return

;*******************************************************************************
; Function:  dec24
; Description: Decrement a little-endian 24 bit number.  Performance between
;  5 and 12 cycles depending on rollovers.
; Parameters:  W - pointer to the 24 bit number
; Returns:  None
;*******************************************************************************
dec24:  
  movwf  FSR  ; decrement the byte pointed to
  decfsz  INDF,F  ; by the indirect register
  incfsz  INDF,W  ; check the indirect register
  return  ; and return if it rolled over

  incfsz  FSR,F  ; decrement the byte pointed to (Inc to point to counter+1)
  decfsz  INDF,F  ; by the indirect register
  incfsz  INDF,W  ; check the indirect register
  return  ; and return if it rolled over

  incfsz  FSR,F  ; decrement the byte pointed to  (Inc to point to counter+2)
  decf  INDF,F  ; by the indirect register
  return



;     ********************* End of interupt service routine *******************


MAIN
; initialise ports
   clrf   INTCON


;  movwf CMCON

;Configure PORTA
   bsf   STATUS,RP0   ; select memory bank 1

   movlw   B'00000000'   ; RA0 to RA4 outputs
   movwf   TRISA     ; port A data direction register
   CLRF   IOCA     ; No interrupt on change for PORTA

;Configure PORTB
   movlw   B'01110000'   ; port B bits 0-3 do not exist, bits 4 - 6 as inputs, Bit 7 output
   movwf   TRISB     ; port B data direction register
   bcf   STATUS,RP0   ; memory bank 0   
   bsf   STATUS,RP1   ; select memory bank 2

   CLRF   ANSEL     ; activate all PORT bits on  PC16F690 as digital
   CLRF   ANSELH

   MOVLW   B'01010000'  ; Weak pull ups on  PORTB bits 4 & 6
   MOVWF   WPUB

   MOVLW   B'01010000'  ;Bits for interrupt on change on PORTB
   MOVWF   IOCB

   bcf   STATUS,RP1   ; select memory bank 0
   bsf   STATUS,RP0   ; select memory bank 1

;Configure PORTC
   MOVLW   B'00000000'   ;All bits set to output
   MOVWF   TRISC

   movlw   B'00000000'   ; TMR0  external clock and prescaler /2,
   movwf   OPTION_REG   ; Pull ups set by WPUA & WPUB registers
   bcf   STATUS,RP0   ; memory bank 0   


;Configure EUSART

   MOVLW   B'10010000'    ;Enable serial port, Continuous Receive Enable bit
   MOVWF   RCSTA
;Needs other things configuring if it is to be used.

;Clear ports
   clrf   PORTA     ; ports clear or low
   clrf   LCD_Port


  bcf  INTCON, GIE  ; Disable interrupts

;Configure LCD display
   call    DELAY_TM     ;Delay added for display to initialize
   call    DELAY_TM
   call    DELAY_TM

   movlw   B'00000011'   ; initialise LCD module
   movwf   LCD_Port
   nop
   CALL   Toggle_E
   call    DELAYms

; set LCD 4-bit operation

   movlw   B'00000010'
   movwf   LCD_Port     ; place display commands in portB
   bcf   LCD_RW     ; R/W low (write)
   bcf   LCD_RS     ; register select low
   nop
   CALL   Toggle_E
   call   DELAYms
   
   movlw   B'00101000'   ; display function (4-bits, 2 lines, 5x8 dots)
   call   LOAD
   movlw   B'00001100'   ; blinking off, cursor off
   call   LOAD
   movlw   B'00000001'   ; display clear
   call   LOAD
   movlw   B'00000110'   ; entry mode. cursor moves right, display not shifted
   call   LOAD
   movlw   B'00000001'   ; display clear
   call   LOAD
   movlw   B'00001100'   ; blinking off, cursor off
   call   LOAD
   call   CLEAR

  clrf  last_sum  ; zero the last sum of samples

   bsf  INTCON,RABIE  ; enable interrupt-on-change of RB4 -RB7 interrupt
  bsf  INTCON,GIE  ; enable interrupts
;  bcf  INTCON,GIE       ;disable interupts for testing !!!!!!!!!

   goto   RESOL       ; "RESOL" is the start of the main program


CLEAR   movlw   A'1'     ; ASCII 0
   movwf   ESEVN     ; ms display digit to zero
   movlw   A'2'
   movwf   ESIX
   movwf   EFIVE
   movwf   EFOUR
   movwf   ETHREE
   movwf   ETWO
   movwf   EONE
   movwf   EZERO     ; ls display digit to 0
;   call   DISP_L     ;
   return
;   *** End of initialization ***




RESOL   

   clrf   FLAG_S     ; This is the start of the main program


     ; This is the start of the main program

   bsf   FLAG_S,0     ;Count update flag This is so the display is loaded at power on

   call   DELAY_TM

;   clrf   BIN1
;   clrf   BIN2
;   clrf   BIN3
;   clrf   BIN4


  clrf  counter  ; zero the counter
  clrf  counter+1  ;
  clrf  counter+2  ;

;   movlw   0x40
;  movwf  counter  ;
;  movwf  counter+1  ;
;  movwf  counter+2  ;

   clrf   REG_A
   clrf   REG_B
   clrf   REG_C

I_Loop       ;Idle loop Loop here until there is a change of quadrature inputs.
   btfsc   FLAG_S,0     ;test for count update
   goto   New_Count   ;Count has changed so update value of Out_Data and LCD display
   Call   Send_Frames   ;Output 2 * 24 bit output frame
   Call   Frame_Delay   ;Delay between frames

   goto   I_Loop
;       End of idle loop

New_Count
;   Copy Quadrature counter value to output counter.

   movf   counter,w
   movwf   Out_Data_2   ;Low byte of 24 bit word to be output
   movf   counter+1,w
   movwf   Out_Data_1   ;Mid byte of 24 bit word to be output
   movf   counter+2,w
   movwf   Out_Data_0   ;High byte of 24 bit word to be output


   btfss   counter+2,7     ;test top bit - Sign bit)
   Goto   POSITIVE
;
;Put code here to deal with negative number
;
   comf   counter,w
   movwf   REG_C
   comf   counter+1,w
   movwf   REG_B
   comf   counter+2,w
   movwf   REG_A

   movlw   REG_C
  call  inc24  ; increment complemented number

;   call   Leftshift2     ;Multiply binary value by 4
   call   BIN_BCD
   call   DISP_L     ;Display the 9 digits on LCD supressing leading 0's
   call   _24Bit_to_hex   ;Display in HEX on bottom line of LCD
   bcf   FLAG_S,0   ;Count update flag
   goto   I_Loop




POSITIVE
   movfw   counter
   movwf   REG_C
   movfw   counter+1
   movwf   REG_B
   movfw   counter+2
   movwf   REG_A

;   call   Leftshift2     ;Multiply binary value by 4

   call   BIN_BCD
   call   DISP_L     ;Display the 9 digits on LCD supressing leading 0's
   call   _24Bit_to_hex   ;Display in HEX on bottom line of LCD
   bcf   FLAG_S,0   ;Count update flag

   goto   I_Loop



;   --------------------- Subroutines  ----------------------------


; delay timer

DELAY_TM
   movlw   0x0F
   movwf   TIME_I     ; initial timer
TIM_CON   call   DELAYms
   decfsz   TIME_I,f
   goto   TIM_CON     ; continue timer
;          ; go to DELAYms
   
; nominal 10us delay loop

DELAYms   
   movlw   0x20     ;Dec 32  for 20 MHz clock
   movwf   STORE1     ; STORE1 is number of loops value

LOOP1
   movlw   0x32     ;Dec 50  for 20 MHz clock
   movwf   STORE2     ; STORE2 is internal loop value   

LOOP2   decfsz   STORE2,f   ;200 ns     0.6 us * 50 = 30 us  + 1 = 31 us
   goto   LOOP2     ;400 ns
   decfsz   STORE1,f   ;200 ns
   goto   LOOP1     ; decrease till STORE1 is zero 400 ns
   return
;
;         ****************
;
;  *** Load command to LCD ****
;Command byte in "W"
LOAD   movwf   D_STO     ; store data   
   swapf   D_STO,w     ; get upper bits and move to low nibble
   andlw   0x0F     ;Mask

   movwf   LCD_Port     ; place display commands
   bcf   LCD_RW     ; R/W low (write)
   bcf   LCD_RS     ; register select low (Command)
   nop
   nop
   bsf   LCD_E     ; enable set
   nop
   nop
   bcf   LCD_E     ; enable clear

   movf   D_STO,w     ; get lower bits
   andlw   0x0F
   movwf   LCD_Port     ; place display commands in
   bcf   LCD_RW     ; R/W low (write)
   bcf   LCD_RS     ; register select low  (Command)
   nop
   nop
   bsf   LCD_E     ; enable set
   nop
   nop
   bcf   LCD_E     ; enable clear
   nop
   nop
   call   BUS_CK     ; check busy flag
   call   DELAY_TM   ;   !!!!!!!!!!!!! IS THIS REQUIRED ????
   return

;         *****************

; Write character to LCD

DRV_LCD   movwf   D_STO     ; store data
   swapf   D_STO,w     ; upper bits to low nibble
   andlw   0x0F   
   movwf   LCD_Port     ; w to port
   bcf   LCD_RW     ; read/write  (Write)  
   bsf   LCD_RS     ; register select   (Data)
   nop
   CALL   Toggle_E   

   movf   D_STO,w     ; lower bits
   andlw   0x0F
   movwf   LCD_Port     ; w to port

   bcf   LCD_RW     ; read/write  (Write)
   nop
   bsf   LCD_RS     ; register select  (Data)
   nop
   CALL   Toggle_E   
   nop
   call   BUS_CK     ; check busy flag
   return             



; check busy flag

BUS_CK   bsf   STATUS,RP0   ; select memory bank 1
   movlw   B'00001111'   ; Change PORTB   bits 0 to 3 to inputs
   movwf   LCD_Tris
   bcf   STATUS,RP0   ; memory bank 0   

   bcf   LCD_RS     ; rs clear
   bsf   LCD_RW     ; R/W high (read)
CK_AGN   bcf   LCD_E
   nop
   nop
   bsf   LCD_E     ; enable high
   nop
   nop
   btfsc   LCD_Port,3     ; check busy flag  (This is a read as far as the LCD is concerned)
   goto   CK_LOW     ; wait till busy flag clear
   bcf   LCD_E     ; enable low
   nop
   bcf   LCD_RW     ; R/W low (write)

   bsf   STATUS,RP0   ; select memory bank 1
   movlw   B'00000000'   ; set PORTB bits 0 - 3 back to outputs
   movwf   LCD_Tris
   bcf   STATUS,RP0   ; memory bank 0   

   return
CK_LOW   bcf   LCD_E
   nop
   nop
   bsf   LCD_E     ; enable high LOW bits accessed
   nop
   nop
   goto   CK_AGN

;           --------------------------------------------
;Toggle the "E" line on the LCD
Toggle_E
       BSF   LCD_E
       NOP
       NOP
       BCF   LCD_E
       RETURN

;           -----------------------------------------


DISP_L           ;Display the 9 digits on LCD supressing leading 0's
   movlw   0x81     ; address of character position on LCD display   
   call   LOAD     ;load address to display
   call   SPACE2     ; 2 spaces

   btfsc   counter+2,7     ;test top bit - Sign bit)
   goto   DISP_N
   movlw   A' '
   call   DRV_LCD
   goto   DISP_E
DISP_N   movlw   A'-'
   call   DRV_LCD

DISP_E
   movlw   0x02     ; first  characters (Number of characters)
   movwf   STORE1

   movlw   ESIX     ; MSD of freq     (10^6)
   movwf   FSR     ;FSR points to decimal digit


Hz2   movf   INDF,w
   call   DRV_LCD     ;Display 10^6 digit
   incf   FSR,f     ;Point to next decimal digit ( 10^5 )


Hz3   movf   INDF,w
   call   DRV_LCD     ;Display 10^5 digit
   incf   FSR,f     ;Point to next decimal digit ( 10^4 )

   movf   INDF,w
   call   DRV_LCD     ;Display 10^4 digit
   incf   FSR,f     ;Point to next decimal digit ( 10^3 )

   movf   INDF,w
   call   DRV_LCD     ;Display 10^3 digit
   incf   FSR,f     ;Point to next decimal digit ( 10^2 )

   movf   INDF,w
   call   DRV_LCD     ;Display 10^2 digit
   incf   FSR,f     ;Point to next decimal digit ( 10^1 )

   movf   INDF,w
   call   DRV_LCD     ;Display 10^1 digit
   incf   FSR,f     ;Point to next decimal digit ( 10^0  ie Units )

   movf   INDF,w
   call   DRV_LCD     ;Display units digit


   call   SPACE1     ;  space
;   movlw   A'm'     ; m
;   call   DRV_LCD
;   movlw   A'm'     ; m
;   call   DRV_LCD
   call   SPACE2     ; 2 spaces
   return


SPACE4   movlw   0x20     ; space
   call   DRV_LCD
SPACE3   movlw   0x20     ; space
   call   DRV_LCD
SPACE2   movlw   0x20     ; space
   call   DRV_LCD
SPACE1   movlw   0x20     ; space
   call   DRV_LCD
   return
;


;           -------------------------------------------

; Subroutine BCD (to convert 28-bit binary to 8-digit BCD)
; Binary value is in BIN1, BIN2, BIN3 & BIN4. BIN1 is LSB, BIN4 is MSB
; Result in BCD is in BCD1, BCD2, BCD3, BCD4 & BCD5. BCD1 is for overrange,
; BCD2 is MSB, BCD5 is LSB

BIN_BCD   movf   REG_A,w     ; ms byte of frequency count
   movwf   BIN3     ; next ms byte
   movf   REG_B,w
   movwf   BIN2
   movf   REG_C,w     ; ls byte of counter
   movwf   BIN1
BINBCDX   clrf   BIN4     ; ms byte
   bcf   STATUS,C   ; clear carry bit
   movlw   D'32'
   movwf   COUNT     ; 32 in count
   clrf   BCD1     ; set BCD registers to 0
   clrf   BCD2
   clrf   BCD3
   clrf   BCD4
   clrf   BCD5

LOOPBCD   rlf   BIN1,f     ; LSB shift left binary registers
   rlf   BIN2,f
   rlf    BIN3,f
   rlf   BIN4,f     ; MSB
   rlf   BCD5,f     ; LSB shift left BCD registers
   rlf   BCD4,f
   rlf   BCD3,f
   rlf   BCD2,f
   rlf   BCD1,f     ; MSB

   decfsz   COUNT,f     ; reduce count value return when 0
   goto   DECADJ     ; continue decimal adjust
   
; result in BCD1-5. (BCD1 overrange, BCD2 MS byte)

   swapf   BCD2,w     ; get ms nibble
   andlw   0x0F
   iorlw   0x30     ; convert to ASCII
   movwf   ESEVN     ; ms digit
   movf   BCD2,w     ; get 2nd ms nibble
   andlw   0x0F
   iorlw   0x30     ; convert to ASCII
   movwf   ESIX

   swapf   BCD3,w     ; get next nibble
   andlw   0x0F
   iorlw   0x30     ; convert to ASCII
   movwf   EFIVE     ; ms digit
   movf   BCD3,w     ; get next nibble
   andlw   0x0F
   iorlw   0x30     ; convert to ASCII
   movwf   EFOUR
   
   swapf   BCD4,w     ; get ms nibble
   andlw   0x0F
   iorlw   0x30     ; convert to ASCII
   movwf   ETHREE     ; ms digit
   movf   BCD4,w     ; get 2nd ms nibble
   andlw   0x0F
   iorlw   0x30     ; convert to ASCII
   movwf   ETWO

   swapf   BCD5,w     ; get ms nibble
   andlw   0x0F
   iorlw   0x30     ; convert to ASCII
   movwf   EONE     ; ms digit
   movf   BCD5,w     ; get 2nd ms nibble
   andlw   0x0F
   iorlw   0x30     ; convert to ASCII
   movwf   EZERO
   return       ; completed decimal to BCD operation

; subroutine decimal adjust

DECADJ   movlw   BCD5     ; BCD LSB address
   movwf   FSR     ; pointer for BCD5
   call   ADJBCD     ; subroutine to adjust BCD
   movlw   BCD4
   movwf   FSR
   call    ADJBCD
   movlw   BCD3
   movwf   FSR
   call    ADJBCD
   movlw   BCD2
   movwf   FSR
   call    ADJBCD
   movlw   BCD1
   movwf   FSR
   call    ADJBCD
   goto   LOOPBCD

; subroutine adjust BCD

ADJBCD   movlw   0x03     ; w has 03
   addwf   INDF,w     ; add 03 to BCDx register (x is 1-5)
   movwf   TEMP     ; store w
   btfsc   TEMP,3     ; test if >7
   movwf   INDF     ; save as LS digit
   movlw   0x30     ; 3 for MSbyte
   addwf   INDF,w     ; add 30 to BCDx register
   movwf   TEMP     ; store w
   btfsc   TEMP,7     ; test if >7
   movwf   INDF     ; save as MS digit
   return       ; end subroutine


Leftshift2     ;Leftshift 24 bit binary number in REG_A,REG, B, REG_C two places (REG_A is MSB)

   bcf   STATUS,C   ;Clear carry bit
   rlf   REG_C,f
   rlf   REG_B,f
   rlf   REG_A,f
   bcf   STATUS,C   ;Clear carry bit
   rlf   REG_C,f
   rlf   REG_B,f
   rlf   REG_A,f
   return
;
;           -------------------------------

;*****************************************************************************   
;
;  Function :  output_hexbyte
;  Outputs the byte in tmpData to LCD
;     (tmpData not changed in this routine ) ?
;  Input:  data in tmpData
;
;  Output:  Data displayed
;
;*****************************************************************************   
output_hexbyte
  swapf  tmpData,W
  sublw  0x09
  swapf  tmpData,W
  andlw  0x0F
  btfss  STATUS,DC
  addlw  'A' - .10 - '0'
  addlw  '0'
  call  DRV_LCD
  movfw  tmpData
  sublw  0x09
  movfw  tmpData
  andlw  0x0F
  btfss  STATUS,DC
  addlw  'A' - .10 - '0'
  addlw  '0'
  call  DRV_LCD
  return


;
;   *************************************************************************************************
;   *   Send Frames                     *
;   *  Function    Output the pair of 3 byte data frames to DRO           *
;   *  Data to be output is in locations Out_Data_0, Out_Data_1, Out_Data_2       *
;   *  !! NOTE both frames of the pair contain the same data            *
;   *************************************************************************************************
Send_Frames         ;Subroutine
         bcf  Clock_out  ; Clear the clock line
       bcf  Data_out  ; Clear the data line


       movlw  2  ; Set the word iterator to 2  (3 byte frames of data ?)
       movwf  frames  ;
   
next_word:
       movlw  Out_Data_2    ; Load the file register pointer  (With LSB of frame)
       movwf  FSR  ; with the address of the data to be sent
   
       movlw  3  ; Set the byte iterator to 3  (3 bytes per frame)
       movwf  bytes  ;
   
       movlw  7  ; Set the bit iterator to 7 (To count bit shifts)
       movwf  bits  ;
   
       bsf  Clock_out  ; Rising clock edge  (Clock set high) (Start of Clock lead in)


;           *** Output state of data bit ***
       btfsc  INDF,0  ; Output data bit 0
       bsf  Data_out
       btfss  INDF,0
       bcf   Data_out

       rrf  INDF,F  ; Advance to next data bit
   
       movlw  DELAY_55US  ; Delay 55 microseconds    (Value = 0xFA)   (This is the start clock pulse)
       movwf  param1  ;
       clrf  param2  ;
       call  delay_cycles  ;
   
       bcf  Clock_out  ; Falling clock edge     (Set clock low)



;           *** Delay 1 bit time ***   
       movlw  DELAY_6_6US  ; Delay 6.6 microseconds  (Value = 0x0A) (Bit time)
       movwf  temp1
delay_1:  
       decfsz  temp1,F
       goto  delay_1
;           End of 6.6 us delay

;

       bsf  Clock_out  ; Rising clock edge  (Set clock high)

next_byte:
next_bit:
       btfsc  INDF,0  ; Output next data bit
       bsf  Data_out
       btfss  INDF,0
       bcf  Data_out
;

       rrf  INDF,F  ; Advance to next data bit
;
;           ; Delay 6.6 microseconds       
       movlw  DELAY_6_6US
       movwf  temp1
delay_2:  
       decfsz  temp1,F
       goto  delay_2
;           End of 6.6 us delay



       bcf  Clock_out  ; Falling clock edge     (Set clock low)

          ; Delay 6.6 microseconds   
       movlw  DELAY_6_6US
       movwf  temp1
delay_3:  
       decfsz  temp1,F
       goto  delay_3
;           End of 6.6 us delay


   
       bsf  Clock_out  ; Rising clock edge     (Set clock high)

       decfsz  bits,F  ; Decrement the bit iterator
       goto  next_bit  ; and continue if not zero
;

       rrf  INDF,F  ; Rotate to the first data bit  (Is this just to leave the byte unchanged ?)
       decf  FSR,F  ; Decrement the file register pointer
       movlw  8  ; Set the bit iterator to 8
       movwf  bits  ;
       decfsz  bytes,F  ; Decrement the byte iterator
       goto  next_byte  ; and continue if not zero


;               *** 55 us delay at end of frame ***   
       movlw  DELAY_55US  ; Delay 55 microseconds
       movwf  param1  ;
       clrf  param2  ;
       call  delay_cycles  ;
;               *** End of 55 us delay ***


       decfsz  frames,F  ; Decrement the word iterator  (I think word means frames !)
       goto  next_word  ; and continue if not zero

;               *** End of frame set clock & data low ***   
       bcf  Clock_out  ; Clear the clock line
       bcf  Data_out  ; Clear the data line
;               *** Frame has now been output ***
;       BCF   Out_Enable     ;Not required (Was for sharing output pins)
       return
;

;     -----------------------------------------------------------------------------
;   *********************************************************************************
;    *  Function:  delay_cycles               *
;    *  Description: Delay a specified number of instruction cycles including   *
;  *  interrupt cycles.  The function call overhead adds between     *
;  *  13 and 16 cycles of delay on top of the specified value.     *
;   *   Timer 1 Prescaler 1:1 Clock Fosc/4  (5Mhz  / 200ns with 20 Mhz xtal)   *
;   *                     *
;    *  Parameters:  param1 - least significant byte of 16 bit cycle delay     *
;  *  param2 - most significant byte of 16 bit cycle delay     *
;    *  Returns:  None                 *
;   *********************************************************************************
delay_cycles:
       
         MOVLW   0x01       ; enable timer1  All other bits 0  1:1 Prescaler ,Internal clock Fosc/4
       MOVWF   T1CON

       comf  param1,F  ; negate the delay by complementing the
       comf  param2,F  ; low and high bytes
       bcf  T1CON,TMR1ON  ; stop timer 1
       movf  param1,W  ; move the low byte of the delay into
       movwf  TMR1L  ; timer 1
       movf  param2,W  ; move the high byte of the delay into
       movwf  TMR1H  ; timer 1
       bcf  PIR1,TMR1IF  ; clear the timer 1 rollover flag
       bsf  T1CON,TMR1ON  ; turn on timer 1
   
tmr1_check:   
       btfss  PIR1,TMR1IF  ; wait for the timer 1 rollover flag to
       goto  tmr1_check  ; trigger
       return
     
;           ----------------------------------


Frame_Delay  ;Delay between frames

   movlw   0x14     ;20 decimal
   movwf   TIME_I     ; initial timer
FD_Loop   call   DELAYms
   decfsz   TIME_I,f
   goto   FD_Loop     ; continue timer

     return

;         ---------------------------------------------
;
;       Code to display HEX value on bottom line

_24Bit_to_hex
;
   movlw   0xC1     ; address of character position on LCD display   Second position on bottom line.
   call   LOAD     ;load address to display
   call   SPACE2     ; 2 spaces

   movf   Out_Data_0,w   ;High byte of 24 bit word to be output
   movwf   tmpData
   call   output_hexbyte   ;Output top two hex characters to LCD
;
   movf   Out_Data_1,w   ;Middle byte of 24 bit word to be output
   movwf   tmpData
   call   output_hexbyte   ;Output middle two hex characters to LCD
;
   movf   Out_Data_2,w   ;Low byte of 24 bit word to be output
   movwf   tmpData
   call   output_hexbyte   ;Output bottom two hex characters to LCD
   return

;
; ++++++++++++++++++++++++


   end
This unit was built to emulate the output of digital calipers so you can leave all the code that does that out.
I hope this can get you started.

Les.
 

Thread Starter

daljeet795

Joined Jul 2, 2018
295
Several years ago I built a unit that displays the output of a quadrature encoder using a

Les.
Hello Les.

Thanks a lot for sharing your circuit and program code. It gives some basic idea But I don't have the part's mentions in your post. I will look to purchase part's mention in a post but if possible I am looking to use hardware part's that are available now

I have another encoder that following information printed on the label

+ wire Wh
- wire Bk
A wire Bn
A/ wire Ye
B wire Rd
B/ wire Gn
Z wire Or (N/C)
Z wire Bl (N/C)
Shield wire shield (N/C)

If I check brown and black wire while rotating shaft slowly it shows (0/24V)

I am looking for advice to interfacing it to pic16f877a. I have optocopler circuit that convert 24V signal into 5V DC

I think it's incremental encoder not quadrature encoder

What should I do to get more experience with it using code?
 
Last edited:

Thread Starter

daljeet795

Joined Jul 2, 2018
295
@daljeet795 There is also Picmicro's with the QEI, Motion Feedback Module, geared towards inputting a quadrature encoder.
Pic18F2331/4431 etc.
Max.
I apologize to take your much time but can you clear to points

  1. Count based rejection on conveyor for moving object
  2. Position based rejection on convyor for moving object
What I think if the speed of conveyor is not variable then we can make Count based rejection using proxi sensor and if the speed of convayor is variable then we have to use encoder to reject object at exact position
 

MaxHeadRoom

Joined Jul 18, 2013
28,699
Incidentally do you need that high of a resolution,
What I think if the speed of conveyor is not variable then we can make Count based rejection using proxi sensor and if the speed of convayor is variable then we have to use encoder to reject object at exact position
Possibly this will be needed, all though a 5k/rev encoder seems a little high for this application.
It could also be done by a simple slot opto and slotted disc or a proximity sensor as I would think precise position and direction that encoder offers is not really needed.
Max.
 

Thread Starter

daljeet795

Joined Jul 2, 2018
295
Incidentally do you need that high of a resolution,Max.
I am using it because I have it only

It could also be done by a simple slot opto and a proximity sensor as I would think precise position and direction that encoder offers is not really needed.
Max.
assume I am not using the encoder and the distance between scanner and rejection is 1100 mm

Okay this is the rough idea that you are saying


upload_2019-3-16_22-34-18.png

I am interested to know How would you do it with proximity sensor ?
 

LesJones

Joined Jan 8, 2017
4,191
From post #34 I get the impression that you are using it with a conveyor system. If this is the case (I am also assuming that the conveyor only moves in one direction.) then you do not need to decode the quadrature signals. Just counting pulses from one output (A or B) should do what you want. So we can give you better advice can you tell us how many revolutions the encoder makes when the conveyor moves 1100 mm and how much time it takes to move that distance. Also how long is the object in the direction of travel. I agree with Max that it seems a very high resolution encoder for your purpose. (It is even possible that using the Z output (One pulse per revolution.) may be good enough.)

Les.
 

Thread Starter

daljeet795

Joined Jul 2, 2018
295
So we can give you better advice can you tell us how many revolutions the encoder makes when the conveyor moves 1100 mm and how much time it takes to move that distance Les.
Circumference = PI * diameter

Distance per revolution = 3.14159 * 50mm = 157mm

So pulses per meter is = 5000 / 0.157 = 31847

Do i need to measure approx 32,000 pulses ?
. Also how long is the object in the direction of travel..).
object size is 85mm
 
Last edited:

MaxHeadRoom

Joined Jul 18, 2013
28,699
I am interested to know How would you do it with proximity sensor ?
I mentioned a small proximity sensor and a slotted wheel, or a gear tooth sensor, similar to a slot opto this would be a simple form of encoder, as the quadrature encoder you have is a little overkill with A-B-Z pulses.
Max.
 

MaxHeadRoom

Joined Jul 18, 2013
28,699
I think it's incremental encoder not quadrature encoder?
It is both! ;)
These are commonly used in servo positioning systems, You actually only need to use the A, B or Z pulse not all three, if long distance between Micro and encoder then A & /A or B & /B.
If a lower resolution solution is used you could use the TMR1 input in counter mode.
Max.
 

Thread Starter

daljeet795

Joined Jul 2, 2018
295
It is both! ;)
These are commonly used in servo positioning systems, You actually only need to use the A, B or Z pulse not all three, if long distance between Micro and encoder then A & /A or B & /B.
If a lower resolution solution is used you could use the TMR1 input in counter mode.
Max.
It would take time to collect part's that you and Les suggested

But I think should try whatever I have, so I think I have to count approx 32,000 pulses to reject object. I know this is not exact pulses but Just want see what happens

So I Just want to do experiments for 30,000, 31,000, 32,000 pulse
 
Top