I am in the process of building a version of AK3Y's Tuna Tin S, which is presented in December 2020's QST. The attractiveness of the project is to replace old style VFO circuits with a low-cost digital synthesizer. I decided to use a Wemos D1 Mini clone for the synthesizer control, rather than the Arduino Nano shown in the QST article. I was able to get the D1 Mini, Si5351 synthesizer breakout, and the KY-040 rotary encoder going pretty quickly on a bread board.
After building a second version wired on a PCB, I noticed that when rotating the encoder knob that the unit was counting frequency up and down erratically. Upon investigation, I found that the encoder had a great deal of switch bounce that was causing misclocking of the counting algorithm in the controller. The photo below shows the signal from the encoder CLK line transitioning from low to high with about 15 usec of switch bouncing. The switch bounce can cause havoc with the rotary encoder counting routine in the controller. Misclocking caused by switch bounce tends to cause the counter to count erratically.
I downloaded AK3Y's Nano program which is written in Arduino IDE, and ported this code over to the D1 Mini. In the article and program, the encoder CLK and DT lines are tied to digital input of the Nano. The CLK falling edge generates an interrupt. The interrupt routine is shown below:
There is some debounce code added to ignore interrupts that occur within 5 ms after a previous interrupt. The frequency gets changed in the interrupt routine. In the main loop if the frequency changes (caused behind the scene during interrupt), then the synthesizer and display are updated with the new frequency.
The principle of operation can be understood by examining the encoder state transition diagram. In the diagram below, the encoder CLK and DT are denoted A and B respectively in the state transition diagram. The encoder signals transition 00 to 10 to 11 to 01 to 00 when rotating clockwise and rotate 00 to 01 to 11 to 10 to 00 rotating counterclockwise. When encoder CLK, which is A, falls it corresponds to the transitions colored red in the diagram. In the lower left, A (CLK) falls, and B (DT) is HIGH when the transition is finished. This transition indicates a clockwise rotation and should generate a count upward. In the upper right transition, A (CLK) falls, and at the end of the transition B (DT) is LOW. This transition is counterclockwise and should generate a count downward. Looking at the interrupt code, which is entered immediately after the fall of encoder CLK, the routine checks DT. If DT is LOW the frequency is decremented, otherwise the frequency is incremented.
I ported this algorithm to the D1 Mini, but upon testing, the frequency counted erratically when the encoder was rotated. I put the encoder up on the scope for diagnosis. For trouble shooting purposes I added a test output of the D1 Mini. This signal falls immediately after the DT is read in the interrupt routine and rises again immediately after the display and the Si5351 synthesizer are updated. I also added the 0.68 uF capacitor on the encoder CLK line. This capacitor is recommended in the AK3Y QST article.
The resulting test signals are shown in the diagram below. The encoder knob was turned two detents counterclockwise over a time interval of about 75 ms. Note that when CLK (green curve) falls, the TEST SIG (yellow curve) goes low, indicating that the interrupt was triggered and the display and Si5351 were updated. However the problem is that the rising edge of CLK also triggered an interrupt, as indicted by the fall of TEST SIG. This is shown at the vertical white line in the diagram. The interrupt pin is specifically setup to trigger on the falling edge of CLK, but often triggers on the rising edge as well. This causes erratic counting in response to turning the encoder knob.
The false triggerings are probably a result of the slow rise of the CLK signal. It is not good practice to drive digital inputs with slow moving signals. The problem was repeatable and occurred using two different D1 Minis. I did not try switching out to a different encoder. It is possible that the Arduino Nano used by AK3Y didn't experience this false interrupt triggering.
I did some more research and found some inspiration on the
Components101.com site. Follow the link and you'll find a KY-040 encoder datasheet and a good discussion of its construction and operation. The test program included with the datasheet used a different algorithm for converting the encoder signals to counts.
Observe the annotated encoder state diagram below. Anytime CLK changes, whether rising edge or falling edge, we can determine the direction of rotation by observing whether the DT signals is the same as CLK, or whether DT is opposite of CLK. In the first case the movement is counterclockwise and the count should be decremented, in the second case the movement is clockwise and the count should be incremented.
I decided to abandon the use of interrupts and determine CLK transitions by polling. I also removed the capacitor off the CLK line. The loop section of the D1 Mini program is shown below. After a check of the encoder push switch, the encoder service section begins at line 73. If a check of the CLK signal shows a transition has occurred, then the encoder service routine is executed, otherwise the loop is begun again. The encoder service is simple. The DT signal is compared to CLK to determine the direction of rotation and the count (in this case a frequency variable) is incremented or decremented accordingly. After that, the display and the Si5351 are updated. A diagnostic test output is toggled to indicate on the oscilloscope that the encoder service routine is active.
The scope traces are shown below. In this case the encoder is rotating counterclockwise. As shown by the test signal, the encoder service routine is entered at every transition, up or down, of the CLK signal. After each transition CLK is always the same state of DT, so the count is decreasing as the knob rotates counterclockwise.
Other tests at very fast time scale show that the latency for detecting a CLK transition by polling is less than 10 us. This is sufficiently fast to avoid misreading the DT signal.
Further the encoder service routine last about 6 ms before the routine returns to polling for a CLK transition again. This is a sufficient delay to provide debounce of the encoder CLK signal. The routine responds to the first valid transition in a bouncy transition and ignores other bounce transitions since it is away on the encoder service routine.