The Sunday Blog: The enhanced “K” HMIs

Part2: More GPIO with a rotary encoder

Two weeks ago, we talked already about the enhanced functionality of the enhanced “K” series (and btw also the intelligent “P” series) Nextion HMIs. In this blog article, we discovered the integrated RTC and we used the Nextion Expansion board in combination with touch screen buttons to adjust it. Sometimes, especially in industrial or other rough environments, touching a small screen is not the best way of interacting, thus, external alternative IO solutions may be put in place.

Today, let’s replace the 6 buttons by a single control, an external rotary encoder with push-button, i.e. a EC12 from Alps. Thus, the small Nextion I/O adapter will be sufficient for our needs.

How does a rotary encoder work?

It’s like a rotary switch with one central pin which is connected to ground and two signal pins, called A and B. These are internally open by default and, as you rotate the knob by 1 detent, will both close and open again which will pull the signal at A and B alternatively to GND. The trick is that this closing happens with a phase shift of 90° which allows to detect the direction. Thus, analyzing the signals in detail will tell you if the knob is turned clockwise or counterclockwise.

For clockwise, from one detent to the next, the sequence is A_down – B_down – A_up – B_up.
Counterclockwise, the sequence is reversed, and thus, logically, the previous rising ramps become falling and vice-versa. So, the sequence is B_down – A_down – B_up – A_up.

Fortunately, there is no need to analyze the sequences in detail, let’s just look at what happens when A_down occurs: When turning clockwise, the signal level at pin B will be high (the B_down hasn’t yet occurred). And when turning counterclockwise, the signal at pin B will be low (the B_up hasn’t yet occurred).

The push-button function is trivial: the switch pin is always high, will go down when you press the button and will go up again when you release it.

… and how to connect it to a Nextion HMI?

For example, we use a very similar GUI and hmi file as two weeks ago. We connect the rotary encoder as follows to the GPIO pins :

SW (the switch pin) => IO_0
GND (the second switch pin and the encoder central pin) => GND
A or CLK => IO_1
B or DT => IO_2

And, in case your encoder breakout board has additional pull-up resistors (these increase greatly the stability):

+ => 5V

Now, the coding:

On page 0 (the only page of this project), we have still the number components to display time and date and a few text components for the separators, as last time. We have a timer tm0 which updates regularly the number components from the RTC with this event code:

n0.val=rtc0
n1.val=rtc1
n2.val=rtc2
n3.val=rtc3
n4.val=rtc4
n5.val=rtc5

In the page preinitialization event, we configure the GPIO, binding the switch (IO_0) to the hidden hotspot m0 to handle the push-button presses, the encoder A pin (IO_1) to the hidden hotspot m1 which contains the cw/ccw logic. The encoder B pin (IO_2) is just configured as input-pullup since we only need to read it at the moment when pin A goes down, which translates in a Touch press event of m1:

cfgpio 0,1,m0 //switch
cfgpio 1,1,m1 //rotary a
cfgpio 2,0,0 // rotary b

As last time, we use internally the variable sys0 to determine if the clock is running normally (sys0=0), or if we are adjusting the year (sys0=1), the month (sys0=2), and so on up to the seconds (sys0=6). Each push-button press increases sys0 by 1 until we arrive beyond 6. Then sys0 is reset to 0. After each change, the display is refreshed and if sys0 is between 1 and 6, the component to be adjusted changes its color from white to orange.

sys0++
if(sys0>6)
{
  sys0=0
}
for(sys2=1;sys2<7;sys2++)
{
  if(sys2==sys0)
  {
    // Set the active field's pco to orange
    b[sys2].pco=64512
  }else
  {
    // Set all but the active field's pco to white
    b[sys2].pco=65535
  }
}

And now the Touch Press event code of the hotspot m1 which detects by reading pio2 if we are turning clockwise or counterclockwise and takes the the increment or decrement action accordingly on the field which is intended to be adjusted as pointed out by sys0:

if(pio2==1)
{
  if(sys0==1)
  {
    rtc0++
  }else if(sys0==2)
  {
    rtc1++
  }else if(sys0==3)
  {
    rtc2++
  }else if(sys0==4)
  {
    rtc3++
  }else if(sys0==5)
  {
    rtc4++
  }else if(sys0==6)
  {
    rtc5++
  }
}else
{
  if(sys0==1)
  {
    rtc0--
  }else if(sys0==2)
  {
    rtc1--
  }else if(sys0==3)
  {
    rtc2--
  }else if(sys0==4)
  {
    rtc3--
  }else if(sys0==5)
  {
    rtc4--
  }else if(sys0==6)
  {
    rtc5--
  }
}

And that’s it. You don’t need to create the hmi project. Just download the file here: rtc_gpio_demo2.HMI, load it onto your 3.5″ enhanced Nextion, wire the encoder and have fun!

Troubleshooting

In case something won’t work as expected, carefully check your wiring! Contact problems with Dupont wires and breadboards might lead to unexpected behavior of the rotary encoder, i.e. counting only up or only down, independent of the turning direction. When you see the rotary action reversed, simply switch the encoder A and B pins. Then, for heaven’s sake, use a quality encoder from Alps, not a cheap clone! The latter introduce contact bouncing and chatter which might mess up the whole sequence, like stuttering: A_down – A_up – A_down – A_up – A_down – A_up – A_down – A_up – over a few milliseconds before the expected transition of pin B (including a similar stuttering) will happen. Unpredictable results guaranteed! 😉
Knowing that the internal pull-up resistors of the Nextion’s GPIO are relatively weak (~50kOhm), you can also try to improve the stability of the readings by adding external 10kOhm pull-ups from pins A, B, and SW respectively, to +5V.

Thank you for reading & have fun rotating!