The Smell of Molten Projects in the Morning

Ed Nisley's Blog: Shop notes, electronics, firmware, machinery, 3D printing, laser cuttery, and curiosities. Contents: 100% human thinking, 0% AI slop.

Category: Electronics Workbench

Electrical & Electronic gadgets

  • Logic Probe Tip Covers

    Our Larval Engineer received a logic probe / pulser set for Christmas:

    RSR Logic Probe Pulser Set - with formed covers
    RSR Logic Probe Pulser Set – with formed covers

    They’re the low-cost RSR-611 and -620 from the usual eBay vendor, not my ancient HP10525/10526 set, but they should suffice. Perhaps nobody uses logic probes these days, what with most of the parts being too small for even a needle tip, but …

    Anyhow, they didn’t have caps over the sharp probe tips, so I rummaged around until I found the stash of cigar tubes (some of which went into that air flow straightener) that were about the right size. I thought about 3D printing an adapter between tubes and probes:

    RSR Probe Cap Adapter - solid model
    RSR Probe Cap Adapter – solid model

    It’s actually a subtractive kind of thing, with a model of the probe tip subtracted from a suitable cylindrical object:

    RSR Logic Probe - solid model
    RSR Logic Probe – solid model

    But then I realized the tubes were thermoplastic, held each one over a stove burner until the open end went transparent and droopy, rammed it down over the probe tip, and trimmed off the ragged edge. Worked fine, fits securely, and even looks pretty good:

    RSR Covers - detail
    RSR Covers – detail

    I’ll never print the adapters, but maybe one of us will tweak the model to do something else…

    The OpenSCAD source code:

    // RSR Logic Probe / Pulser Cap
    // Ed Nisley KE4ZNU December 2012
    
    // Adapts cigar tube to probe body
    
    // Layout options
    
    Layout = "Build";
                        // Overall layout: Show Build
    			// Parts: Probe
    
    //- Extrusion parameters must match reality!
    //  Print with +1 shells and 3 solid layers
    
    ThreadThick = 0.25;
    ThreadWidth = 2.0 * ThreadThick;
    
    HoleWindage = 0.2;
    
    function IntegerMultiple(Size,Unit) = Unit * ceil(Size / Unit);
    
    Protrusion = 0.1;           // make holes end cleanly
    
    //----------------------
    // Dimensions
    
    ProbeDia = 18.0;				// dia of main body
    ProbeTipDia = 6.8;				// dia at end of plastic cone
    ProbeTipLen = 30.0;				// length of metal ferrule + tip
    ProbeConeLen = 17.5;			// cone taper length
    
    TubeOD = 17.25;
    TubeWall = 0.50;
    TubeID = TubeOD - 2*TubeWall;
    
    TubeLen = 15;					// slip fit over tube body
    
    BodyLen = 20;					// slip fit over probe body
    
    WallThick = 3.5*ThreadWidth;		// basic adapter wall thickness
    
    AdapterLen = TubeLen + BodyLen;
    AdapterOD = ProbeDia + 2*WallThick;
    AdapterSides = 4*4;
    
    //----------------------
    // Useful routines
    
    module PolyCyl(Dia,Height,ForceSides=0) {           // based on nophead's polyholes
    
    Sides = (ForceSides != 0) ? ForceSides : (ceil(Dia) + 2);
    
    FixDia = Dia / cos(180/Sides);
    
    cylinder(r=(FixDia + HoleWindage)/2,
             h=Height,
             $fn=Sides);
    }
    
    module ShowPegGrid(Space = 10.0,Size = 1.0) {
    
        Range = floor(50 / Space);
    
        for (x=[-Range:Range])
            for (y=[-Range:Range])
                translate([x*Space,y*Space,Size/2])
                %cube(Size,center=true);
    
    }
    
    module Probe() {
    	union() {
    		cylinder(r=((ProbeDia + HoleWindage)/2),
    				 h=(BodyLen + 1.2*Protrusion),$fn=2*AdapterSides);
    		translate([0,0,(BodyLen + Protrusion)])
    			cylinder(r1=(ProbeDia + HoleWindage)/2,
    					 r2=ProbeTipDia/2,
    					 h=ProbeConeLen,$fn=2*AdapterSides);
    		cylinder(r=ProbeTipDia/2,h=(BodyLen + ProbeConeLen + ProbeTipLen),$fn=2*AdapterSides);
    	}
    }
    
    module ProbeSleeve() {
    
    	difference() {
    		cylinder(r=AdapterOD/2,h=AdapterLen);
    		translate([0,0,-Protrusion])
    			Probe();
    		PolyCyl((TubeOD + HoleWindage),(AdapterLen + Protrusion),2*AdapterSides);
    	}
    }
    
    //----------------------
    // Build it!
    
    ShowPegGrid();
    
    if (Layout == "Show")
        ProbeSleeve();
    
    if (Layout == "Build")
        translate([0,0,AdapterLen])
    		rotate([180,0,0])
    			ProbeSleeve();
    
    if (Layout == "Probe")
    	Probe();
    
  • Cheap LED Flashlight Switch Disassembly

    The pushbutton switch on the end cap of a cheap LED flashlight became intermittent, for reasons that should be obvious:

    LED Flashlight switch - intact
    LED Flashlight switch – intact

    Pulling the spring contact out revealed the usual situation inside:

    LED Flashlight switch - spring removed
    LED Flashlight switch – spring removed

    I thought that the discolorations around the central plug indicated a solder joint between the two, but the scratches showed that the plug was actually a press-fit plastic cylinder. Having nothing to lose, I pried the rubber dome off the outside of the switch, balanced the cap’s outer rim on the bench vise, centered an aluminum cylinder over the switch post, and gave it a hammer shot:

    LED Flashlight switch - guts
    LED Flashlight switch – guts

    It appears the Basement Warehouse Wing inventory lacks a push-on switch that fits the cap, so this one goes on the pile of potentially useful parts. If a suitable switch appears, I know what to do with it, but if I should need a nice aluminum cylinder that fits a trio of AA cells before then, well …

  • Tektronix 2215A Oscilloscope Power Switch Rebuild

    My trusty Tek 2215A oscilloscope might be useful for a Larval Engineer engaged in late-night debugging away from the lab, but the power switch has become flaky: sometimes the ‘scope didn’t turn on at all, sometimes the switch required multiple pokes, sometimes everything worked fine. Removing the cover revealed there’s a long plastic bar connecting the power button on the front panel (to the right in the picture) to the power switch near the rear panel AC line socket, tucked under the EMI filter with the red sticker:

    Tek2215A - internal top view
    Tek2215A – internal top view

    Removing the high voltage shield below the PCB reveals the switch has DPDT terminals, but it’s wired as DPST:

    Tek2215A power switch - PCB terminals
    Tek2215A power switch – PCB terminals

    This knowledge will come in handy later…

    Unsoldering the switch and wriggling the bar out of the front panel puts the switch on the bench, solder terminals upward. A plastic shell snapped around the actual switch insulates the top of the six terminals from prying fingers:

    Tek2215A power switch - bottom
    Tek2215A power switch – bottom

    Remove the shell, remove the toggle-action U-shaped steel pin, release the spring, and pull off the top plate:

    Tek2215A power switch - internal
    Tek2215A power switch – internal

    Remove the plunger hardware, remove the rocker arms and their springs:

    Tek2215A power switch - disassembled
    Tek2215A power switch – disassembled

    One contact on each rocker shows signs of distress, but the other button remains pristine (having never seen any voltage differential):

    Tek2215A power switch - rockers
    Tek2215A power switch – rockers

    Pull out the fixed contact tabs and note that they’ve been scorched a bit. The one on the right corresponds to the bottom rocker above:

    Tek2215A power switch - contact tabs
    Tek2215A power switch – contact tabs

    I cleaned everything with a fiber wipe wetted in DeoxIT, then decided that I’d take the easy way out. The tabs have heavy silver plate on both sides, so I flipped them over and reinstalled them with the unused side facing the rockers. The rockers went back in with their unused contact buttons facing the flipped tabs, so we now have fresh, shiny new contact surfaces. Reassemble the switch, soldered it in place, button up the case, and a firm push on the button lights the ‘scope exactly the way it should.

    While I had the cover off, I measured the ESR of all those electrolytic capacitors: they’re in fine shape!

    The next time the switch needs repair, in another couple of decades, someone can swap in the completely unused tabs from the other end of the switch, then pick whichever contact buttons look best… [grin]

  • 5 mW Laser Module

    A trio of 5 mW laser modules arrived with a bunch of other surplus gear after an end-of-year sale:

    5 mW Laser Module
    5 mW Laser Module

    It runs on 5 V at 20 mA, determined by the 91 Ω SMD resistor soldered across the terminals at the back of the PCB. That suggests the laser diode itself runs at about 3.2 V: 5 V – 0.020 A * 91 Ω.

    The brass case connects to the red (positive) wire, so you must insulate the laser module from the usual grounded metal chassis.

    Two of the three lasers arrived badly defocused, but a twist of the brass barrel broke the sealing glue and a bit more twiddling found the sweet spot.

    Running one of these from an Arduino would be just like the UV LED: redefine a bit in the shift register bitfield and drive the laser with a MOSFET switch.

    I’d be tempted to bypass the SMD resistor and run it from an LM317-style current regulator hitched directly to the raw battery; I’m pretty sure I have some LM317 regulators in TO-92 packages. The sense resistor would be 62.5 Ω = 1.25 V / 0.02 A, dissipating 25 mW = 1.25 V * 20 mA. From a freshly charged 7.2 V Li-ion battery at 8.5 V, the regulator would dissipate something like 80 mW =(8.5 – 1.25 – 3.2 V) * 20 mA.

    Or just add more series resistance and ignore the brightness variation?

  • Traffic Signals: Green LED Failures

    Traffic Signal - dead green LEDs - 2012
    Traffic Signal – dead green LEDs – 2012

    In our (admittedly limited) travels around New York State during the last half decade or so, I’ve seen many (as in, dozens of) traffic signals with this failure:

    Apparently the topmost LED string burns out first, leaving the other two (?) strings intact. The earliest picture I have dates back to 2008, so this is a problem of long standing that’s probably wiped out any projected maintenance cost reduction for the entire purchase. The most recent failure I spotted, a few weeks after taking this picture, has a flickering upper string that means it’s not long for this world.

    Somewhere up around Albany, I recently saw a green signal with only that string lit up and the other two (?) strings dead, but that’s the sole exception to the pattern.

    Of late, NYS DOT has been installing a different green lamp with the LEDs in each string scattered over the entire surface and no diffuser. That means a failed string, of which I’ve already seen several examples in the area, darkens a few spots without being particularly obvious; a less common failure has a few flickering “pixels” that will eventually go dark. While that’s a net win, I wonder why only green lamps have this problem: we very rarely see red or amber lamps with any failed LEDs.

    One red LED lamp down the road did fail spectacularly: the whole thing flashed, slowly and somewhat irregularly. Not a flicker, but a flash: long off and short on.

    It’s hard to get pictures of failed traffic signals…

    While I suppose I should report them, previous attempts to do so have only led to requests for the ID number of the traffic control box, which generally can’t be seen from the traffic lane. I am not stopping at an intersection, getting out, finding the box (perhaps crossing the intersection to get there), finding the ID number, and taking a picture for later reference; you know what happens to people who take pictures of infrastructure. You’d think the signals could phone home on their own, but they’re likely not connected.

  • Arduino Snippets: LED Stroboscopic Tachometer

    A bit of fiddling with the Arduino PWM hardware can turn a white LED into a stroboscopic tachometer to chop smooth motion into chunks:

    Strobe - Maze 1 - 50 Hz 100 us
    Strobe – Maze 1 – 50 Hz 100 us

    I was moving that pendant by hand and slight speed changes were easily visible:

    Strobe - Maze 2 - 50 Hz 100 us
    Strobe – Maze 2 – 50 Hz 100 us

    IBMers of a certain era may recognize the test object; the rest of you can go there.

    That’s a 10 mm warm-white LED with 5 parallel chips, running at about 100 mA from a 5 V supply, and driven from the same PWM channel and MOSFET that used to drive also drives the red channel of the RGB LED Mood Light:

    White LED Strobe
    White LED Strobe

    The ZVNL110A MOSFET has a 3 Ω drain resistance, which becomes a significant part of the resistance; you’d want a bigger, better, lower resistance MOSFET to wring more light out of the LED. In fact, I ran the LED from 12 V with the same resistor at a few hundred mA.

    The reason you need more light is to make up for the minuscule duty cycle. In order to “stop motion”, you want a very short pulse; I picked a 100 μs pulse. At 50 Hz, that works out to a 0.5% duty cycle: not much light at 100 mA, but OK for a demo.

    You can’t do this with the standard Arduino PWM setup, because it produces a constant frequency (about 488 Hz) and varies the duty cycle; we need a variable frequency with a constant pulse length. Because a stroboscope needs fine-grained control over the frequency, in order to stop the motion of rotating objects, it should run from one of the 16 bit Timer1 PWM outputs, which means either PWM9 or PWM10. Note that simply changing the timer’s clock prescaler as described there won’t suffice, because that gives very coarse control of the PWM frequency.

    It’s probably worth noting that trying to do precise timing purely in software with, say, the millis() and micros() functions, produces terrible results…

    The Arduino timer hardware includes control over both the period and the duration of the output pulses. The Fine Manual describes all the timer configuration registers starting on page 109; see that post for a push-pull PWM driver that formed the basis of this one.

    Fast PWM (Mode 14) has some useful characteristics:

    • Single-slope operation: timer counts only upward
    • Output PWM9 goes high when TCNT1 resets to 0
    • Output PWM9 goes low when TCNT1 = OCR1A
    • TCNT1 resets when TCNT1 = ICR1

    The lowest possible output frequency occurs with ICR1 = 0xffff, so that Timer1 counts from 0x0000 to 0xffff before resetting (which, in that case, is indistinguishable from simply wrapping). The wrap period = ICR1 * tick period and the corresponding frequency = 1 / period.

    The clock prescaler determines the overall range of Timer1 by setting the tick period. The Clock Select bit field can take on 6 useful, albeit widely separated, values (the other two select the external clock pin):

    • 0 – stop timer
    • 1 – prescale 1:1 = 62.5 ns tick → 244 Hz
    • 2 – prescale 1:8 = 500 ns tick → 30 Hz
    • 3 – prescale 1:64 = 4 μs tick → 3.8 Hz
    • 4 – prescale 1:256 = 16 μs tick → 0.95 Hz
    • 5 – prescale 1:1024 = 64 μs tick → 0.24 Hz

    For my purposes, a lower limit around 4 Hz seemed about right. That means CS = 3, the prescaler runs at 1:64, and the timer ticks at 4 μs.

    The frequency upper limit could be just under 1/(pulse width), which would produce a very high duty cycle. I arbitrarily set the limit to 1/(4 × pulse width), for a 25% duty cycle that works out to 1/(4 × 100 μs) = 2.5 kHz = 150 k flash/min. If you’re using very high current drive, then limit the duty cycle to prevent toasting the LED.

    Because a strobe tach needs quick & easy adjustment, the encoder knob tweaks the pulse frequency in 1 Hz steps. Pushing the knob to close the shaft switch (if you have such a knob, of course, otherwise use another button; they all do the same thing here) reduces the step size to 0.01 Hz, which is more useful for fine tuning when you’re close to the goal. A real application requires better control over the numeric values (probably using integer values); I used floating point and simply ignored all the usual roundoff issues:

    Stroboscope Tachometer
    Ed Nisley - KE4ZNU - December 2012
    Frequency: 10.00
    Pulse duration: 100 us
    Frequency: 11.00
    Frequency: 12.00
    Frequency: 13.00
    Frequency: 14.00
    Frequency: 14.01
    Frequency: 14.02
    Frequency: 14.02
    Frequency: 14.02
    Frequency: 14.01
    Frequency: 14.00
    Frequency: 13.98
    Frequency: 13.97
    Frequency: 13.97
    Frequency: 13.96
    Frequency: 13.94
    Frequency: 13.93
    Frequency: 14.93
    Frequency: 15.93
    Frequency: 16.94
    Frequency: 17.94
    

    Updating the counter period requires:

    • Shut off interrupts to prevent interference with the high byte storage register
    • Stop the timer: CS=0
    • Load the new upper limit in ICR1
    • Force TCNT1 to be just below IRC1 to terminate the current pulse
    • Start the timer: CS=3
    • Enable interrupts again

    You’d probably plunk that into a separate function in a real program…

    Printing the frequency becomes a hassle without floating point formatting in printf(). It should appear on the character LED display, too. Optionally / additionally showing the value in rev/min would be very nice.

    You’d want to increment the frequency by some reasonable fraction of the current value, perhaps rounded to 1 / 2 / 5 / 10 percent steps. Larger steps by pushbutton? Truncate the current value to a multiple of the step size?

    You would also want some way to adjust the flash duration, but that’s definitely in the nature of fine tuning.

    As it stands, a 100 μs pulse really does stop motion:

    Fan stopped at 2500 rpm
    Fan stopped at 2500 rpm

    That’s a fan running at about 2500 rpm, with the LED flashing at 41.86 Hz. The camera exposure is 1/2 sec @ f/3.5, handheld, which means the camera integrated about 20 flashes. Ambient light accounts for the background blur: I boosted the grossly underexposed image right out of darkness. The square on the hub is retroreflective tape for a laser tachometer that verified the speed.

    Yes, half a second handheld. The morning tea wears off during the day…

    In round numbers, 41.86 Hz = 23.9 ms / rev. The fan diameter is 86 mm, so the blade tips travel 1.1 mm = (270 mm / 23.9 ms) × 100 μs during each flash. The tips seem slightly blurred when you (well, I) look very closely in real life, but I think this lashup worked pretty well right off the sketchpad.

    The Arduino source code:

    // Stroboscopic Tachometer
    // Ed Nisley - KE4ANU - December 2012
    
    //----------
    // Pin assignments
    
    const byte PIN_KNOB_A = 2;			// knob A switch - must be on ext interrupt 2
    const byte PIN_KNOB_B = 4;			//  .. B switch
    const byte PIN_BUTTONS = A5;		//  .. push-close momentary switches
    
    const byte PIN_STROBE = 9;			// LED drive, must be PWM9 = OCR1A using Timer1
    
    const byte PIN_PWM10 = 10;			// drivers for LED strip, must turn these off...
    const byte PIN_PWM11 = 11;
    
    const byte PIN_SYNC = 13;			// scope sync
    
    //----------
    // Constants
    
    const int UPDATEMS = 10;				// update LEDs only this many ms apart
    
    #define TCCRxB_CS 0x03					// Timer prescaler CS=3 -> 1:64 division
    
    const float TICKPD = 64.0 * 62.5e-9;	// basic Timer1 tick rate: prescaler * clock
    
    enum KNOB_STATES {KNOB_CLICK_0,KNOB_CLICK_1};
    
    // ButtonThreshold must have N_BUTTONS elements, last = 1024
    
    enum BUTTONS {SW_KNOB, B_1, B_2, B_3, B_4, N_BUTTONS};
    const word ButtonThreshold[] = {265/2, (475+265)/2, (658+475)/2, (834+658)/2, (1023+834)/2, 1024};
    
    //----------
    // Globals
    
    float FlashLength = 0.1e-3;						// strobe flash duration in seconds
    word FlashLengthCt = FlashLength / TICKPD;		//  ... in Timer1 ticks
    
    float FlashFreq = 20.0;							// strobe flash frequency in Hz
    float FlashPd = 1.0 / FlashFreq;				//  ... period in sec
    word FlashPdCt = FlashPd / TICKPD;				//  ... period in Timer1 ticks
    
    float FreqIncr = 1.0;							// default frequency increment
    const float FreqMin = 4.0;
    const float FreqMax = 1.0/(4.0*FlashLength);
    
    volatile char KnobCounter = 0;
    volatile char KnobState;
    
    byte Button, PrevButton;
    
    unsigned long MillisNow;
    unsigned long MillisThen;
    
    //-- Helper routine for printf()
    
    int s_putc(char c, FILE *t) {
      Serial.write(c);
    }
    
    //-- Knob interrupt handler
    
    void KnobHandler(void)
    {
    	byte Inputs;
    	Inputs = digitalRead(PIN_KNOB_B) << 1 | digitalRead(PIN_KNOB_A);  // align raw inputs
    //	Inputs ^= 0x02;                             // fix direction
    
    	switch (KnobState << 2 | Inputs) {
    	case 0x00 : 				// 0 00 - glitch
            break;
    	case 0x01 : 				 // 0 01 - UP to 1
            KnobCounter++;
    		KnobState = KNOB_CLICK_1;
    		break;
    	case 0x03 : 				 // 0 11 - DOWN to 1
            KnobCounter--;
    		KnobState = KNOB_CLICK_1;
    		break;
    	case 0x02 : 				 // 0 10 - glitch
            break;
    	case 0x04 : 				 // 1 00 - DOWN to 0
            KnobCounter--;
    		KnobState = KNOB_CLICK_0;
    		break;
    	case 0x05 : 				 // 1 01 - glitch
            break;
    	case 0x07 : 				 // 1 11 - glitch
            break;
    	case 0x06 : 				 // 1 10 - UP to 0
            KnobCounter++;
    		KnobState = KNOB_CLICK_0;
    		break;
    	default :  					// something is broken!
            KnobCounter = 0;
    		KnobState = KNOB_CLICK_0;
    	}
    }
    
    //-- Read and decipher analog switch inputs
    //		returns N_BUTTONS if no buttons pressed
    
    byte ReadButtons(int PinNumber) {
    
    word RawButton;
    byte ButtonNum;
    
    	RawButton = analogRead(PinNumber);
    
    	for (ButtonNum = 0; ButtonNum <= N_BUTTONS; ButtonNum++){
    		if (RawButton < ButtonThreshold[ButtonNum])
    			break;
    	}
    
    	return ButtonNum;
    
    }
    
    //------------------
    // Set things up
    
    void setup() {
    	pinMode(PIN_SYNC,OUTPUT);
    	digitalWrite(PIN_SYNC,LOW);	// show we arrived
    
    	analogWrite(PIN_PWM10,0);			// turn off other PWM outputs
    	analogWrite(PIN_PWM11,0);
    
    	analogWrite(PIN_STROBE,1);			// let Arduino set up default Timer1 PWM
    	TCCR1B = 0;							// turn off Timer1 for strobe setup
    	TCCR1A = 0x82;						// clear OCR1A on match, Fast PWM, lower WGM1x = 14
    	ICR1 = FlashPdCt;
    	OCR1A = FlashLengthCt;
    	TCNT1 = FlashLengthCt - 1;
    	TCCR1B = 0x18 | TCCRxB_CS;			// upper WGM1x = 14, Prescale 1:64, start Timer1
    
    	pinMode(PIN_KNOB_B,INPUT_PULLUP);
    	pinMode(PIN_KNOB_A,INPUT_PULLUP);
    
    	KnobState = digitalRead(PIN_KNOB_A);
    	Button = PrevButton = ReadButtons(PIN_BUTTONS);
    
    	attachInterrupt((PIN_KNOB_A - 2),KnobHandler,CHANGE);
    
    	Serial.begin(9600);
    	fdevopen(&s_putc,0);				// set up serial output for printf()
    
    	printf("Stroboscope Tachometer\r\nEd Nisley - KE4ZNU - December 2012\r\n");
    
    	printf("Frequency: %d.%02d\nPulse duration: %d us\n",
    		   (int)FlashFreq,(int)(100.0 * (FlashFreq - trunc(FlashFreq))),
    		   (int)(1e6 * FlashLength));
    
    	MillisThen = millis();
    
    }
    
    //------------------
    // Run the test loop
    
    void loop() {
    
    	MillisNow = millis();
    
    	if ((MillisNow - MillisThen) > UPDATEMS) {
    
    		digitalWrite(PIN_SYNC,HIGH);
    
    		Button = ReadButtons(PIN_BUTTONS);
    		if (PrevButton != Button) {
    			if (Button == N_BUTTONS) {
    //				printf("Button %d released\n",PrevButton);
    				FreqIncr = 1.0;
    			}
    			else
    //				printf("Button %d pressed\n",Button);
    //				if (Button == SW_KNOB)
    					FreqIncr = 0.01;
    			PrevButton = Button;
    		}
    
    		if (KnobCounter) {
    			FlashFreq += (float)KnobCounter * FreqIncr;
    			KnobCounter = 0;
    
    			FlashFreq = constrain(FlashFreq,FreqMin,FreqMax);
    			FlashFreq = round(100.0 * FlashFreq) / 100.0;
    
    			FlashPd = 1.0 / FlashFreq;
    			FlashPdCt = FlashPd / TICKPD;
    
    			noInterrupts();
    			TCCR1B &= 0xf8;				// stop Timer1
    			ICR1 = FlashPdCt;			// set new period
    			TCNT1 = FlashPdCt - 1;		// force immediate update
    			TCCR1B |= TCCRxB_CS;		// start Timer1
    			interrupts();
    
    			printf("Frequency: %d.%02d\n",
    				   (int)FlashFreq,(int)(100.0 * (FlashFreq - trunc(FlashFreq))));
    		}
    
    		digitalWrite(PIN_SYNC,LOW);
    
    		MillisThen = MillisNow;
    	}
    
    }
    

    That’s a grandiose name for a blinking LED, if I ever saw one…

  • LED Stress Tester: Current

    Maybe Eks has forgotten that he loaned me a Tek AM503 Hall effect current probe, which is exactly the right instrument to measure LED currents without introducing any series resistance. In order from the top, we have the amber, red 4-6, red 1-3, and red 7-9, with a scale of 20 mA/div (scope at 10 mV/div):

    LED Current - Tek Hall probe - Y R2 R1 R3
    LED Current – Tek Hall probe – Y R2 R1 R3

    The currents increase by 10 to 20 mA during the pulse, which suggests that the 25 °C thermal change I estimated based on the forward voltage really happens. The power supply decreases pretty much as a 120 mV step and doesn’t vary all that much during the pulse, so I think the LEDs control the current.

    Here’s the forward voltage drop screenshot again for comparison (without the amber LEDs):

    Red LED - group Vf
    Red LED – group Vf

    Overall, they run close enough to 100 mA for my simple needs…