My Retro Challenge this year is to get rotary encoders working on my RC2014 computer.
Previously, I explained what a rotary encoder was, how to use one, and how to link it to the RC2014.
I now want to try reading it on the RC2014 and using it to control some output.
I’m using the SC219 Digital I/O Board on the RC2014 to accept inputs from a rotary encoder. I have mine mapped to I/O address port 0. Using Microsoft BASIC I can read this using the INP(0) statement. This will return a byte representing the values of D0 to D7 on the input port.
I am using D0 for the CLK, D1 for DT, and D2 for SW. D3 to D7 are not used at the moment. I am only interested in D0 and D1 for the rotary motion. I can use AND statements to mask bits when I’m checking the input value. So to check if D0 was 1 or 0, I could use INP(0) AND 1. This would return either 0 or 1. To check D1, I could use INP(0) AND 2. This would return either 0 or 2.
The following UML activity diagram shows at a high level how I need my BASIC program to operate.
The Microsoft BASIC on the RC2014 is old and limited compared to modern languages, but it is functional.
To save space, I’ll use variable A for CLK, and B for DT. I’ll need to keep track of the last state of A so I know when it has changed. To do this I’ll create a variable LAST_A. Finally, to keep track of the INP(0) result, I’ll create variable INPUT.
When I detect a change in A, I need to look to see if B matches A. If it does, then I know the encoder is being turned to the right. If it doesn’t, then it is being turned to the left.
Here is the BASIC code I came up with to do this. When it detects a change, it prints either “Left” or “Right” to the console.
10 LET LAST_A = 0
20 LET IN = INP(0)
30 LET A = IN AND 1
40 IF A = LASTA THEN GOTO 200
50 LET B = IN AND 2
60 IF (A=1 AND B=2) OR (B=0 AND A=0) THEN GOTO 100
80 PRINT "Right"
90 GOTO 200
100 PRINT "Left"
200 LET LAST_A = A
210 GOTO 20
The SC219 has digital outputs as well as inputs. Using the built-in output LEDs, I can move a dot left or right depending on the input from the rotary encoder.
The 8 output LEDs represent each bit of a byte. So we have the values 1, 2, 4, 8, 16, 32, 64, and 128 represented on bits D0 to D7. This is 2 to the power X, where X is between 0 and 7. We can use the ^ (power) operator in BASIC to help set these bits.
So we need to have a variable, let’s call it COUNTER, to keep track of which power we are currently at. We can say turning the rotary encoder left will increment COUNTER by 1. Turning the rotary encoderrigtht will decrement COUNTER by 1. We need some guards, so if COUNTER goes below 0, we set it to 7. If it goes above 7, we set it to 0. We set one of the LEDs by using OUT 0,2^COUNTER. This means when we turn the rotary encoder, we can move the LED.
Here is the BASIC code I wrote to do this.
10 LET COUNTER = 0
20 LET LAST_A = 0
30 LET IN = INP(0)
40 OUT 0,2^COUNTER
50 LET A = IN AND 1
60 IF A = LASTA THEN GOTO 200
70 LET B = IN AND 2
80 IF (A=1 AND B=2) OR (B=0 AND A=0) THEN GOTO 150
90 IF COUNTER <= 0 THEN GOTO 120
100 LET COUNTER = COUNTER - 1
110 GOTO 130
120 LET COUNTER = 7
130 PRINT "Right"
140 GOTO 200
150 IF COUNTER >= 7 THEN GOTO 180
160 LET COUNTER = COUNTER + 1
170 GOTO 190
180 LET COUNTER = 0
190 PRINT "Left"
200 LET LAST_A = A
210 GOTO 30
Here is a short video of it in action.