Archives for the month of: December, 2019

When you wire a button or a switch into a digital circuit, it might seem as though when the button is pushed, a circuit is closed, and there’s a digital HIGH or 1 available.

It’s not that straightforward, unfortunately. At the microscopic scale, the switch has tiny burrs that connect and disconnect several (or hundreds) times before it settles closed so that current can flow. This is called “bouncing,” and it’s the topic of many really great videos and blogposts. I even wrote one a few years ago, but now I have an oscilloscope so I can dig in a lot more deeply.

Mostly people handle it in software: if you see a button press, ignore everything for (about) the next 100ms, so you only count one press. A similar technique is to poll the button frequently, watching for a series of HIGH values, then counting only once it’s HIGH for a long enough period.

I am going to follow this video and report my findings (also a nice diagram and roundup of simple software techniques in this post). Here’s a picture of what button bouncing looks like.

The button is wired on one leg to ground, and on the other leg, through a 10K resistor which connects to 3.3v. The probe is attached to the 3.3v side of the resistor. When I push the button, there’s an initial jump to 3.3 that lasts only about 120 nanoseconds (the solid white vertical line marks when I pushed, and I zoomed in to measure the time of the first bounce). After about 100μs (note that microsecond is abbreviated μs), the contact gets a little closer, and the jumps upward become more insistent. At about 240μs after I pushed the button, the button settles at a HIGH signal (note the dashed vertical line when this happens). I released the button only another 100μs later, and it dropped nicely to LOW (note that there’s not usually much bouncing when a switch opens because all the little rough bits are pulled apart more quickly than when they are closing).

The Teensy 4.0 I’m using here runs at 600MHz, about 6 cycles/μs. So there are more than 1500 cycles during the 262μs this button is bouncing. It’s easily capable of counting the 8-10 bounces above 1.8v (where it counts HIGH). That creates a mess when you’re trying to count button pushes.

For my test, I’m doing 2 separate things to the signal. First, I smooth the bouncing using a resistor-capacitor (RC) circuit. I can’t explain RC circuits, that’s a bit above my skills so far, but I recommend the Art of Electronics Lab Course, chapter 2. I’m digging through it now.

When the switch closes, the capacitor discharges according to the time constant, τ = R x C. The idea is that it takes about 5τ for the RC circuit to charge or discharge. The charging is exponential, not linear, and there’s a great tutorial about it here but alas, the graphics seem to be missing.

My graphics aren’t great, but here they are. R1 is the pullup resistor, and it’s 2K. The RC circuit starts with R2 at 680Ω and the capacitor is 1μF. That means that τ = 6.8e-4 secs, so it charges or discharges in 5τ = 3.4ms.

This is what happens when I press the button and measure the signal in parallel with the RC (before IC1 in the schematic above). Note that the two vertical lines mark the beginning and end of the capacitor’s discharge. BX-AX is about 4.6ms, which is pretty close to the theoretical 5τ = 3.4ms. I’m happy when my experiments match theory.

The point of this is to get a digital signal to the microprocessor, but the RC signal isn’t really square, it’s curved which forces the microprocessor to decide when the signal is HIGH. The Teensy can do that, of course, but once we start building this circuit, shouldn’t we get a square signal out of it?

The answer is an inverting Schmitt trigger, an integrated circuit that shifts from 1 to 0 at some higher threshold, and from 0 to 1 at a lower threshold. It’s an inverting trigger, which means that it’s output is always the opposite of the input, as seen in the image above. The yellow line is from the RC circuit which is the input to the trigger. For the trigger, I’m using a 74HC14, an integrated circuit (i.e., a chip) which switches from high to low when the input voltage hits about 1.8v (when the input voltage to the chip is 3.3v).

Note that as the yellow line gently climbs, when it hits 1.8 volts, BAM, the Schmitt trigger output shown by the blue line drops from HIGH to LOW. The datasheet reports that the drop happens in about 7-19ns; My oscilloscope sees the transition in 14.8ns: good job, datasheet. By comparison, the CPU on the Teensy is running at 600mHz, which means about one cycle takes 1/600th of a million-th of a second, which is approximately 2 nanoseconds. While it only takes one cycle to read the digital pin (in the very best case, usually it’s more), the Arduino is doing other stuff and can’t check the pin every cycle, so it won’t read the pin more than every 50-100 ns. The Schmitt trigger switches in about 15ns, 8x slower than the CPU. There’s very little chance chance that the Teensy will be confused during the trigger’s transition.

Here’s what it looks like wired.

The code that runs the counter is below. I’ve banged on this button something fierce, and it counts once and only once every time I hit it. There’s no software debouncing at all, the hardware is doing all the work.

I like it! It’s pretty unnecessary: I’ve found that a simple delay works for nearly all my applications, and in exceptional cases like rotary encoders, state machines work a treat. However, I’m really happy to have had a reason to look more deeply into this topic and to have another tool in my kit if a switch acts up.

/*
   testing button press counts 
   wylbur, 25 Dec 2019
*/

const int CHIP_PIN = 15; 
int chip_count = 0; 
int last_chip_count = -1; 

void setup() {
  //start serial connection
  Serial.begin(57600);
  pinMode(CHIP_PIN, INPUT_PULLDOWN); 
  attachInterrupt(digitalPinToInterrupt(CHIP_PIN), isrChip, RISING);
  Serial.println("init complete."); 
}


void loop() {
  if (chip_count != last_chip_count) {
     Serial.print(millis()); 
     Serial.print(F(": chip=")); 
     Serial.println(chip_count); 
     last_chip_count = chip_count; 
  }
}


void isrChip() {
  chip_count++; 
}

// done. 

My friend Bear was on the BM cleanup crew this year, and he came upon a seriously tricked-out bike that had been abandoned, locked to a bike rack at a big sound camp. He removed the electronics for me to study. There are 8 strands of analog (not individually-addressed) 12v RGB LEDs, like this one.

So 8 * 3 (RGB) connections (each of which sinks) is a quick tip here. Of course there’s an Arduino.

Then it gets more interesting for me. The Arduino sends a serial signal to a series of 3 74HC595N shift registers, thereby splitting the serial signal into 24 (ahem, 8 * 3) parallel 5v outputs.

But the LEDs are 12v, and will need to sink a lot of current. Here’s where the lost inventor does something I would not have thought of: they used 3 ULN2803AN ICs to sink a lot of current (again 24 signals, but at 12v!), switched by the Arduino at 3.3v.

Note that the ULN2803ANs are stacked, one on top of another, putting them in parallel so each output can sink up to 1A. Good thinking, and careful soldering.

There’s a lot for me to learn with this teardown. Using the ULN2803AN as an array of Darlington transistors is pretty cool. I’ve used single Darlingtons before, and it seems that arrays of transistors and resistors is something I’m learning about right now (more on this in a later post).

Even more, the inventor has srsly used perf board before. They organized the chips and the headers to minimize the wiring in smart ways that I’m going to keep studying.

It sure is great to have a lab to study stuff like this! Thx to Bear for spotting this in the dust and schlepping it home for me.