Dual Quadrature Decode

Warning: if you clip this code into your program, look out for possible html code slipping in.

REM   Dual quadrature decode example for SBC2000-074 and SBC2000-062
REM
REM   Author: Steven R. Wheeler
REM
REM   Copyright 1999 Vesta Technology, Inc.
REM   All rights reserved.
REM
REM   Revision history:
REM     Nov. 9, 1999     First version.


REM   This example decodes the 4 upper lines on port B (normally used
REM   as keypad inputs) as two pairs of quadrature inputs. We do this
REM   with a state machine. The two quadrature channels are on the
REM   keypad connector (pins 5 and 6 are channel 1, and pins 7 and 8
REM   are channel 2).
REM
REM   We will use the ON INT0 capability of VSTB to keep from missing
REM   any transitions (up to the maximum rate we can sustain). We will
REM   require four variables: the current quadrature count for each
REM   input pair, and an error count for each input pair. The error
REM   count will be incremented each time we get an illegal transition.
REM   This would be an indication that the signals are changing faster
REM   than we can handle them.
REM
REM   The "output" for each quadrature channel is the count variable,
REM   which can be thought of as representing a position. This will
REM   be in the range -32768 to +32767. This routine does not take
REM   any action when the count wraps from "most positive" to "most
REM   negative" and vice-versa. This can be done, but will limit the
REM   top end of quadrature input speed.
REM
REM   The information provided by the error counts is only how many
REM   transitions we think we have missed. We can't really use it to
REM   adjust the counts unless we know we're always incrementing or
REM   always decrementing.

REM   Because we have 4 lines we are monitoring in pairs, we will end
REM   up with 16 separate cases to handle. We will define a 16x16
REM   constant array to tell us which case to use.
REM
REM   This array is indexed using the previous state of the input lines
REM   and the current state of the input lines as the indices into the
REM   array. The contents of the array element tell us what actions
REM   must be taken. The possibilities are:
REM
REM      0 - do nothing
REM      1 - increment the channel 1 count
REM      2 - decrement the channel 1 count
REM      3 - increment the channel 1 errors
REM	 4 - increment channel 2 count
REM	 5 - increment channel 2 count, increment channel 1 count
REM	 6 - increment channel 2 count, decrement channel 1 count
REM	 7 - increment channel 2 count, increment channel 1 error
REM	 8 - decrement channel 2 count
REM	 9 - decrement channel 2 count, increment channel 1 count
REM	10 - decrement channel 2 count, decrement channel 1 count
REM	11 - decrement channel 2 count, increment channel 1 error
REM	12 - increment channel 2 error
REM	13 - increment channel 2 error, increment channel 1 count
REM	14 - increment channel 2 error, decrement channel 1 count
REM	15 - increment both error counts

DIM Transitions[16,16] AS BYTE CONSTANT = [
	 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15,
	 2,  0,  3,  1,  6,  4,  7,  5, 10,  8, 11,  9, 14, 12, 15, 13,
	 1,  3,  0,  2,  5,  7,  4,  6,  9, 11,  8, 10, 13, 15, 12, 14,
	 3,  2,  1,  0,  7,  6,  5,  4, 11, 10,  9,  8, 15, 14, 13, 12,
	 8,  9, 10, 11,  0,  1,  2,  3, 12, 13, 14, 15,  4,  5,  6,  7,
	10,  8, 11,  9,  2,  0,  3,  1, 14, 12, 15, 13,  6,  4,  7,  5,
	 9, 11,  8, 10,  1,  3,  0,  2, 13, 15, 12, 14,  5,  7,  4,  6,
	11, 10,  9,  8,  3,  2,  1,  0, 15, 14, 13, 12,  7,  6,  5,  4,
	 4,  5,  6,  7, 12, 13, 14, 15,  0,  1,  2,  3,  8,  9, 10, 11,
	 6,  4,  7,  5, 14, 12, 15, 13,  2,  0,  3,  1, 10,  8, 11,  9,
	 5,  7,  4,  6, 13, 15, 12, 14,  1,  3,  0,  2,  9, 11,  8, 10,
	 7,  6,  5,  4, 15, 14, 13, 12,  3,  2,  1,  0, 11, 10,  9,  8,
	12, 13, 14, 15,  8,  9, 10, 11,  4,  5,  6,  7,  0,  1,  2,  3,
	14, 12, 15, 13, 10,  8, 11,  9,  6,  4,  7,  5,  2,  0,  3,  1,
	13, 15, 12, 14,  9, 11,  8, 10,  5,  7,  4,  6,  1,  3,  0,  2,
	15, 14, 13, 12, 11, 10,  9,  8,  7,  6,  5,  4,  3,  2,  1,  0
]


REM   Define the variables we need.

GLOBAL Chan_1_Count AS INTEGER		: REM   Lower pair "position" value
GLOBAL Chan_1_Error AS INTEGER		: REM   Lower pair missing transitions
GLOBAL Chan_2_Count AS INTEGER		: REM   Upper pair "position" value
GLOBAL Chan_2_Error AS INTEGER		: REM   Upper pair missing transitions


REM   This is our interrupt handler. The value passed in is a 4-bit
REM   quantity representing the state of the lines on the upper 4
REM   bits of port B. Case 0 is not included in the SELECT statement
REM   because no action is required for that case.
REM
REM   Note that we get an interrupt on each transition of each line
REM   in each quadrature pair. This means that the count values will
REM   increment 4 times during each waveform period. With no other
REM   processing going on, the shortest quadrature period with which
REM   the system will be able to keep up is about 5.5 msec on a
REM   revision 4 SBC2000-074.

VITAL SUBROUTINE Quadrature(lines AS INTEGER)
STATIC last_lines AS INTEGER
	SELECT Transitions[last_lines, lines]
		CASE 1
			Chan_1_Count = Chan_1_Count + 1

		CASE 2
			Chan_1_Count = Chan_1_Count - 1

		CASE 3
			Chan_1_Error = Chan_1_Error + 1

		CASE 4
			Chan_2_Count = Chan_2_Count + 1

		CASE 5
			Chan_1_Count = Chan_1_Count + 1
			Chan_2_Count = Chan_2_Count + 1

		CASE 6
			Chan_1_Count = Chan_1_Count - 1
			Chan_2_Count = Chan_2_Count + 1

		CASE 7
			Chan_1_Error = Chan_1_Error + 1
			Chan_2_Count = Chan_2_Count + 1

		CASE 8
			Chan_2_Count = Chan_2_Count - 1

		CASE 9
			Chan_1_Count = Chan_1_Count + 1
			Chan_2_Count = Chan_2_Count - 1

		CASE 10
			Chan_1_Count = Chan_1_Count - 1
			Chan_2_Count = Chan_2_Count - 1

		CASE 11
			Chan_1_Error = Chan_1_Error + 1
			Chan_2_Count = Chan_2_Count - 1

		CASE 12
			Chan_2_Error = Chan_2_Error + 1

		CASE 13
			Chan_1_Count = Chan_1_Count + 1
			Chan_2_Error = Chan_2_Error + 1

		CASE 14
			Chan_1_Count = Chan_1_Count - 1
			Chan_2_Error = Chan_2_Error + 1

		CASE 15
			Chan_1_Error = Chan_1_Error + 1
			Chan_2_Error = Chan_2_Error + 1

	ENDSELECT
	last_lines = lines
	SET INT0 TO 1
END


REM   Upon powerup, these will be initialized to zero anyway. This just
REM   gives us clean counts if we're in debug mode and restarting under
REM   command from the IDE.

Chan_1_Count = 0
Chan_1_Error = 0
Chan_2_Count = 0
Chan_2_Error = 0


REM   Set up the handler for decoding the quadrature counts.

ON INT0 Quadrature
SET INT0 TO 1


REM   Direct print output to the LCD. You DO NOT want to have your
REM   application doing a lot of printing to the serial ports, because
REM   it will severely limit the maximum quadrature rate the system
REM   will be able to handle without problems.

PIPE PRINT LCD

REM   Now a simple application to give us an idea of what's going on.

DO WHILE 1
	LCD_Command(0x80)
	PRINT Chan_1_Count, "    "
	LCD_Command(0x8A)
	PRINT Chan_1_Error, "    "
	LCD_Command(0xC0)
	PRINT Chan_2_Count, "    "
	LCD_Command(0xCA)
	PRINT Chan_2_Error, "    "
LOOP