Switch Debouncing

#1

Hello people,

I’m into electronics for two months now, so please bear with me.

I’m making an 8-step sequencer with the same functionality as intellijel metropolis (I hope) but instead for the pitch sliders, I’m using rotary encoders and a small i2c oled screen.

Each encoder features a button, so pressing each button changes the sequencer edit mode, and by using the encoders you can change the octave, the note length, the note pattern etc.

Right now the sequencer sends midi messages but I intent to change that to CV hopefully after understanding how to send specific voltages using a dac (I think I will manage after studying how CVpal works).

Another change I want to make is to get rid of the arduino I’m using to drive all these and use a barebones atmega, but right now, I feel that I need the input protection, the pin labelling, the usb powering/ programming.

Now, as I said, I’m using 8 encoders and I’m multiplexing their pinAs using an 4051, I’m multiplexing their pinBs using another 4051 and I’m multiplexing their pin their buttons using yet another 4051.

For each pin and button, in my code, I’m using a flag to mark every one that has been changed since the last loop. If so, utilising an array of timestamps for each item, I mark an do-not-read-again period for it. Thus I’m debouncing all my mechanical inputs.

The code works pretty good but it is using the arduino millis() function which is timer dependent and at some point I will have to use the atmega timers to make a precisely timed device.

So I though I could use a hardware (or hardware assisted) debouncing method. I 've read about using capacitors and a Schmitt trigger with hysteresis, and I’ve read something about a trick involving a shift register (I’ve read this in this forum).

You basically wait until all 8 bytes of the register fill up with the same digit and then you read its value.

I searched on avrlib and I found the debounced switch code uses this technique but I cannot understand it precisely as I’ve barely used C.

  1. The code says that the read function should be called at a rate of < 100Hz, how is this accomplished? In arduino we have a loop function. In barebones avr programming are we using another kind of loop function that can be timed, or are we using timers for calling some functions?
  2. If we have 8 encoders do we need 16 shift registers, or can we multiplex them using two muxes and have two shift registers?
  3. What are the principles of debouncing a switch/ button/ encoder using a shift register? Do we load the register as soon as we detect a change on the switch, or something else?
  4. How do we manage the clock pin of the register in order to load the values of the switch?
  5. Which module does use the encoders library, so I can try to study its code?

Thank you!

0 Likes

#2
  1. If you’re doing anything timing critical in your main loop() you’re probably doing it wrong.

  2. Use timers! For example, you can have a timer at 1kHz that does all UI-related things.

  3. If you have 8 encoders, you have 16 pins to read. You can either use two parallel to serial converters (74hc165); but there are options like I/O expansion ICs (MCP23S17).

  4. Are you talking about using a shift register IC to read multiple buttons/encoders using few IO pins on your main MCU; or using a software shift register (as done in avrlib) to debounce? The idea used in avrlib is to store the 8 most recent states of the button in a byte. If it’s 00000000 you know that it’s in stable low position. 11111111 and it’s in a stable high position. Anything else and it’s bouncing.

    1. Ambika, MIDIpal and the Shruthi all use encoders.
1 Like

#3

2&3. I though that the shift_register code in avrlib was used to control an actual shift register. :frowning:

So I’ll create an interval based function using timers that will read the stored values of my two (or three if I include the encoder buttons) shift registers every x time. Do I still need to debounce them? I reckon that the reading interval will be eliminating the bouncing of the switches but I cannot leave that to chance. Would a virtual a-la avrlib would do?

Thank you for the answers :slight_smile:

0 Likes

#4

Yes: encoders need to be read at a fast rate if you don’t want to miss pulses; and at that rate you’re going to see bounces.

0 Likes

#5

Thank you!

0 Likes

#6

It is to control a shift register. DebouncedSwitch debounces a single switch, DebouncedSwitches debounces a group of 8*n switches behind n 74h165s.

Given that it is code that I wrote about 10 years ago, it would help if you gave pointers to specific lines of code!

0 Likes

#7

switch_array
Located.
Today’s task: Study.
:slight_smile:

0 Likes

#8

If i am reading this right https://github.com/pichenettes/eurorack/blob/master/grids/grids.cc#L245
Emilie is using a prescaler before the debounce routine is called.
Is there someone that can explain to me why this is necessary?

0 Likes

#9

Because the TIMER2_COMPA_vect ISR is called at 10kHz (IIRC… it might be 8kHz though), fast enough to track changes in the clock input without introducing too much jitter/latency.

If you scan switches at this rate, it’s likely that a bounce will last through more than the 8 samples of the byte keeping tracking of the past states – you might see 00000000 or 11111111 but the switch might still be bouncing. There is no reason for scanning switches at such a fast rate! So I divide this 10kHz clock rate by 10, and only read/debounce the switches at 1kHz.

1 Like

#10

When the read function is called, the switch state gets shifted to the left and either a 1 or 0 gets appended to the end of the state.

Later on, when you request the state of the switch you have the lowered (10000000), the raised (111 1111), the high (11111111) and the low (00000000) state.

Why do we distinguish between those states? Why there isn’t only the raised and the low state?

0 Likes

#11

Depending on your application you might want to detect when a switch has just been pressed or released (to initiate an action), or just check if it is being held or not (for example to check for button combos).

0 Likes

#12

So what is the difference between low/ lowered and high/ raised?
How can these values be produced especially the lowered (10000000). Is it a state produced by a read of 1 followed by seven reads of 0 (it doesn’t make any sense, so probably my assumption is wrong).

0 Likes

#13
  • low: the switch is held pressed (00000000) – we have read a 0 for 8 consecutive reads.
  • lowered: the switch has recently been pressed (10000000) – we have read 0 for 7 consecutive read, but before that it was a 1, which indicates that it was still high (or bouncing).
1 Like

#14

Got it!
Thank you

0 Likes

#15

Just to be clear, the high state is the initial state and a switch that has been changed state, cannot fall back to this (it is 9 bits).
Right?

0 Likes

#16

I don’t understand. I don’t understand the bit about 9 bits.

And of course a switch can be in the high state, if it’s been released more than 8ms ago (assuming the scan rate is 1kHz).

0 Likes

#17

I got confused, I thought that 0xff was (1 1111 1111) and not (01111111).
Silly me, sorry.

Thank you for your help!
:slight_smile:

0 Likes