## PCB Software Choices

I have an imminent decision looming, and I’m hoping that spelling it out in a blog post will help frame my thoughts. <lie>It’s a tough one, with serious short- and long-term consequences either way.</lie>

I know, it’s up there with the biggest of ethical dilemmas, like that one about killing people on train tracks (I forget the details). But have no fear, let’s first state the reason why I need to think about it.

Currently, I use the free version of Eagle, the popular PCB package from Cadsoft (and heavily promoted by Element14). This is fine for me. I don’t need more layers or a larger board size. BUT, I’m hoping to start selling some stuff on Tindie. And the license for the free version of Eagle doesn’t let you use it for commercial purposes. I think that clause is aimed at businesses making hundreds of boards, not hobbyists who will be lucky to sell one. But still, I feel that Cadsoft are doing good by providing a free version of their software, and it would be morally wrong to exploit that good for profit.

KiCAD is an open-source PCB package that’s also very popular. It appears to have come on leaps-and-bounds recently, and (excitingly) CERN have put someone on it full-time. That’s the kind of awesome stuff CERN does. Moving to KiCAD would eliminate the licensing issue.

Here’s all the pros and cons of this momentous decision:

Stick with Eagle Move to KiCAD No new learning curve Sparkfun/Adafruit etc. libraries available No need to port old PCBs to new software No cost for selling stuff Supporting open-source software ~£70 cost for the right license, which I might not ever make back Paid version still has limits on layers and board size Closed-source software MASSIVE learning curve If I want to sell an old board, need to port it across to KiCAD Seems to be fewer libraries/standard components than Eagle

Looking at this, all the cons of the “stick with Eagle” option after fairly minor compared to those for KiCAD. Closed-source isn’t really that big of an issue for me, I can afford the £70, and I don’t expect that the board limits will be an issue in the long term. My only concern is that the £70 will be wasted if I don’t sell much on Tindie.

After all this, it looks like I’m sticking with Eagle. £70 is less than ten hours at a UK living wage (reckoned at £7.65 per hour). I’d waste at least that much time learning KiCAD before I’d even start using it. While I don’t really think measuring my free time that way is completely fair or reliable, it’s a useful metric. And in this case, I think it’s a valid one. Either way I’m spending money or time, and I think my time is worth more here.

You have been hearing my brain think.

## Mains Frequency Display

I seem to be making a lot of displays lately. Here’s another one.

# Design Concept

I’ve had this planned for a while. The concept is to display the frequency of the UK mains electricity supply. This is meant to be 50Hz, but the frequency actually fluctuates around this value, as a result of changes to supply and demand.

If the frequency drops, it’s because demand has risen and/or supply has dropped, so generators have to work harder. This slows then down a bit, and the control systems take time to speed them back up.

If the frequency rises, it’s because demand has falled and/or extra supply has come on, so generators have to work less. This increases their speed a bit, and the control systems take time to slow them down.

So the frequency is constantly rising and falling. You can see a real-time graph of the last 60 minutes on the national grid website, and a nice real-time analog-style meter at the Dynamic Demand website.

I wanted to make a display that could show the mains frequency to 3 decimal places. I’d be using the same seven-segment display modules that I used in my UNIX clock, so all I had to do was design the part that would work out the frequency.

# How to work out the frequency

There are lots of techniques to do this. My choice was to count a fixed number of mains frequency periods and time how long that takes to occur.

Here’s a drawing of the concept: The sine waves represent the mains. A high-frequency signal is run in parallel and used as a counter. The count after a fixed number of cycles is inversely proportional to frequency.

The concept of measuring a varying low-frequency signal.

For example, if the frequency was exactly 50.000Hz, and I counted 200 periods, that would take exactly 4 seconds. If the frequency was actually 50.001Hz, 200 periods would only take 3.99992 seconds.

That’s not a lot of difference! In order to time that accurately, I need a high-accuracy, high-stability timing source. The RC oscillator in the microcontroller wouldn’t do. I would be using an ATTINY84, which has an accuracy of only +/- 10%, or +/- 1% after user calibration. Nor could I use an external crystal, without paying a LOT of money for a high-stability one.

Luckily, there is one class of cheap(ish) ICs that have high-accuracy, high-stability oscillators in them, and that’s real-time clocks. The DS3231 RTC chip, which was also used in the UNIX clock, has a +/- 2ppm 32.768kHz output. By counting pulses from this, I can determine the time very precisely.

# Maths!

After doing some maths, I figured that I could count for 100 mains cycles (2 seconds at 50Hz) and get my required accuracy.

The formula to translate count to mains frequency is

$f=\frac{1}{\frac{\frac{C}{32768}}{N}}$

where N is the number of mains cycles counted and C is the number of 32768 Hz cycles counted.

I re-arranged this, and added a 1000x multiplier in order to only use integer maths, so 50.000Hz would actually be stored as 50000. This is much nicer for implementing on a microcontroller.

$f = \frac{32768 * N * 1000}{C}$

Because we’re doing integer maths, we need to account for rounding, so the final formula is

$f = \frac{(32768 * N * 1000)+\frac{C}{2}}{C}$

For example, a count of 65724 would equate to a frequency of 49.857Hz, stored as 49857. A count of 65723 would equate to a frequency of 49.858Hz, stored as 49858.

So, a change of one count represents a change of one significant figure (of the scaled frequency), exactly what I want.

The frequency value is sent directly to the display, so the frequency shown is updated every two seconds.

There are two LEDs on the control PCB to display the up/down trend of the frequency. The frequency is stored in a ring buffer once a minute. A ten-minute rolling average is calculated, and the difference between the first and last readings is used to work out the trend. A difference of more than +/- 0.02hz is counted as a significant trend.

In order to find the “best” algorithm for this, data from the National Grid real-time display was parsed with the Beautiful Soup python module. I just experimented with various guesses until it looked about right.

Putting it all together

I tested the code on an Arduino with an opto-isolated mains input before designing the final circuit. The electronic design draws on a lot of previous work I’ve done. It has:

• The mains-frequency input from my Days-Accident-Free counter.
• (This clamps a 9V AC signal (from a small wall-wart transformer) to the 5V supply rails)
• The display connection and DS3231 RTC from the UNIX clock.
• A standard ATTINY84 microcontroller from a host of other projects.

The system block diagram

I was able to reduce the board size down to be the same size as a seven-segment display, which was nice. I ordered the boards from Ragworm, and everything worked first time, which was nice.

The only modification I made was to add a small “heatsink” to the 5V regulator. The input to the system is 9V AC from a small adaptor. Because the regualtor runs all 5 displays, it’s dumping about 1W of power into a rather small package. It gets pretty hot, so I added a heatsink made of lots of solder on a bit of stripboard. A bit of a hack, but it does help keep the regulator cooler than it would be.

The control PCB, with LEDs, microcontroller, power supply and “heatsink”.

Finally, I made a laser-cut case (as is practically standard for my projects). It was an adaption of the UNIX clock casing. For the up and down trend LED symbols, I tried using crayon wax melted into two laser-etched arrows. This worked pretty well, so I think I might use this technique on future projects.

The completed display, showing a “down” frequency trend.

The frequency trend of interest

Posted in Electronics | Tagged , , | 10 Comments

# A Problem

## The Arduino IDE tries too hard to be nice.

Here’s some Arduino code from a recent project of mine:

enum state_enum
{
STOPPED,
ACCEL,
RUNNING,
DECEL
};
typedef enum state_enum STATE_ENUM;
static STATE_ENUM currentState;
static void setState(STATE_ENUM newState)
{
/* Extra code omitted for clarity */
currentState = newState;
}
void setup()
{
/* Extra code omitted for clarity */
setState(STOPPED);
}
void loop()
{
/* Extra code omitted for clarity */
setState(RUNNING);
}

We’ve got a state variable that can be in one of four states, and a function to change state.
Looks OK, right? Well, try compiling it and you’ll get the following error:

sketch_dec04a:3: error: variable or field 'setState' declared void
sketch_dec04a:3: error: 'STATE_ENUM' was not declared in this scope

Which essentially means that on line 3 of my code, the compiler has found a datatype called “STATE_ENUM”, in the setState function, and doesn’t know what that means. But how can this be, when the function isn’t defined here, but about a dozen lines further down?

Turns out that the Arduino IDE (as part of its pre-compile process) scans your code looking for functions, generates prototypes for them and sticks them just above your actual code.

So, this line:

static void setState(STATE_ENUM newState);

Was being inserted above the declaration of the STATE_ENUM type, which causes the compiler to quite rightly say that it has no idea what STATE_ENUM is.

I can see why Arduino have done this: it means inexperienced programmers can put functions anywhere in their sketch and not have to deal with prototyping them.

## Possible Solutions

So, how DO you use user defined types in your Arduino sketch?

### Only use standard types

Well, the messy way is to avoid using functions that return or use those types. So, I could have altered my setState function to be

static void setState(int newState)
{
/* Extra code omitted for clarity */
currentState = (STATE_ENUM)newState;
}

This is a bit messy, as it hides the intent of the function input a bit.

Another option is to put the enumeration and typedef in a header file and #include it. The file is included before the auto-generated prototypes, so the compiler is happy.
This again is a bit messy, and not in the spirit of hiding implementation detail. If nothing else needs to know about your datatype, it shouldn’t be in a header file.

### Hide the function from the auto-generator

Finally, the Arduino website build process page gives us a clue how we can solve this:

“Also, this generation isn’t perfect: it won’t create prototypes for functions that have default argument values, or which are declared within a namespace or class.”

So, we can make the function have a default argument:

static void setState(STATE_ENUM newState = STOPPED)
{
/* Extra code omitted for clarity */
currentState = newState;
}

…which will successfully compile, but now risks being called without an argument, which has the potential to do harmful things.

For the uber-paranoid, you could add an extra “invalid” value to the enumeration, make this the argument default, and test for this value right at the start of your function:

static void setState(STATE_ENUM newState = INVALID_STATE)
{
if (newState == INVALID_STATE) { return; } // Do nothing if called without a state!
/* Extra code omitted for clarity */
currentState = newState;
}

The main disadvantage of this is that ALL the arguments after the defaulted one also need to have defaults. For example, this won’t compile:

static void setState(STATE_ENUM newState = INVALID_STATE, int anotherArg)

Because anotherArg needs a default value. This might be annoying.

## The REAL solution

Ultimatley, the real solution is for the Arduino IDE to allow you to turn off automatic prototyping. Interestingly, an “Arduino for Visual Studio” application does exactly that.

There are LOADS of ways to do this, but I think a nice work-around would be a comment-style function decorator. Something like this:

static void setState(STATE_ENUM newState)/*NOPROTO*/

The Arduino build process would recognise the NOPROTO comment and suppress output of a prototype for that function.

This would avoid adding extra options to either the IDE or the preferences.txt file, and allow individual control of which functions are affected. A downside is that if you have a LOT of functions like this, the code gets littered with /*NOPROTO*/ everywhere.

## What do I do?

Well, for the specific project above, I just modified the function to use a standard type.

I don’t tend to use the Arduino IDE much, so I think what I do in future will depend on the application.

Remember the mantra: “Software development IS decision making.” Get it tattoo’d on your eyeballs.

# Shapes of Constant Width

I’d got my hands on a set of these shapes at a Festival of the Spoken Nerd (FOTSN) show in Nottingham.

I’ve simplified Wikipedia’s explanation of what these things are:

“A shape of constant width is a shape whose width (defined as the perpendicular distance between two parallel lines each touching shape’s boundary) is the same regardless of the rotation of the shape.”

Or you can watch the maths gear video about then:

This means that if you roll these shapes between two rulers, the rules will stay the same distance apart. Magic!

The shapes I got were laser-cut plywood. I’d been toying with the idea of mounting them in a display to show off their movement between two surfaces, but actually they sat unloved in a pile of other stuff for ages.

Then, last August I took a trip to the Edinburgh Fringe, where FOTSN were on. I took the opportunity to get the shapes signed by Matt Parker, Helen Arney and Steve Mould. I dashed off to Edinburgh Hackspace afterwards to get the FOSTN logo laser-etched onto the remaining shape. After this, they could stay unloved no longer.

Here’s a video of the stand I built. You can read a bit more about it below the video.

## Stand Design

My initial idea was to replicate the linear “between two rulers” motion, but I pretty soon changed to a circular design, where a central drive wheel would move the pieces round in a track, just by friction between the surfaces. Observe this rubbish exploded view:

An awful concept drawing of the shapes-of-constant-width stand

The stand holds the motor and any control electronics. A living hinge is a nice way to get it standing up. I had to divide the stand with a fancy wavy line (not a sine wave, that was a silly thing not to think of) into two to fit each piece into the laser.

The retaining ring is glued to the stand. The centre rotating piece was cut to allow for a rubber band to go around it to try and get good grip between the wheel and the shapes.

Everything was designed in Inkscape.

I was hoping that the shapes would rotate without needing holding in from the front, but they kept popping out from between the ring and drive wheel, so I had to add a front retaining piece to the design.

I didn’t just want to cut a boring circle of perspex, so keeping with the maths theme I thought about some sort of grid or spiral.

I settled on the following shape, with was constructed out of overlaid golden spirals:

1. Generating a golden spiral.
2. Copying and rotating it twice.
3. Copying the result, mirroring it and overlaying on the original.
4. Thickening and outlining the paths to allow for cutting.
5. Adding a small circle to the centre and adding the retaining ring.
6. Adding a 3mm centre hole for motor shaft and 3mm screw holes around the edge.

I think it looks quite nice.

Due to the tolerances of the design, and probably in no small part to my own ineptness, the shapes move too freely in some places and stick in others. I solved this by adding some foam to the outside edge of the track, which takes up these non-uniformities.

I also had to add some extra pieces to the cover to stop the shapes being pushed upwards and getting stuck.

THEN I had to drill out the centre of the motor shaft and epoxy in a screw and washer to finally stop everything going wrong.

## Motor and Drive Electronics

The best speed for rotation seemed to be about 10rpm, so I got a 12V 10rpm motor off eBay for about £10. In basic tests, it actually drives the shapes round comfortably at about 6V.

During initial testing, the shapes occasionally stuck, causing a pile-up and the motor stalling. I thought I might have to design some kind of stall sensing and recovery circuit, but luckily with the changes to stop them sticking, and sanding down the edges of the shapes, that wasn’t necessary. I just added a PWM speed control with an Arduino Nano. The Arduino also reverses the direction of rotation every 30 seconds, in the hope that this might average out and long-term drift of the shapes relative to each other.

I might experiment with side-lighting the perspex in the future, maybe just a single LED at the bottom of the piece to draw attention to it.

## An open letter to coalition MPs

Dear Coalition MP,

When watching PMQs, I am disheartened by David Cameron and Ed Milliband arguing like children with bad scriptwriters. I am disheartened by the obfuscation and outright lies.

But that’s all I am. Disheartened. I have come to expect it, and I can at least dismiss it as irrelevant puppetry.

What makes me truly angry is YOUR behaviour. Your fawning and toadying is reprehensible. This does not constitute a suitable question to ask the PM:

“Would the Prime Minister agree that he is brilliant, we are brilliant, and the opposition smell of dog turds and socialism?”

But it seems that’s all you ask.

We elect you to represent us. Not to ask questions that just lead David Cameron into another crap speech.

Find some moral muscle and join the opposition in questioning the decisions your leaders make. Your respective parties should be able to cope with answering questions from within. It’s not a betrayal. It’s democracy.

Yours,

James

Posted in Uncategorized | 1 Comment

## UNIX Clock

This project took more time and money than I’d planned. It was meant to be a quick one that I could get done in a few weeks, without a lot of complex code or new things to learn.

The idea is a just to make a clock to display UNIX time. For those that don’t know, this is simply a count of the number of seconds since 00:00 on 1st January 1970. As I write this post, we’re on 1383053948. Lots of computer systems use this system to internally store time. The time currently needs ten digits to display, and that will do until Sat, 20 Nov 2286 17:46:39, which should be long enough.

So, I was just going to do a clock that had ten seven-segment displays and counted up in seconds. I decided to go with:

• An Arduino Pro Mini board for the controller
• A USB micro connector + breakout board for power
• Two buttons to set the date/time
• An RTC chip to store the time
• A display board of my own design

I thought it would just be this (simple, right?):

A system-level view of the really simple UNIX Clock

Every one of these things except the buttons would cause delays and hassle. Let’s see why.

## Displays

The normal way to drive multiple seven-segment displays to multiplex them; that is to only turn on one display at a time, and rely on our rubbish, slow, biological eyes to make it seem as if all of them are on at once.

This approach has the benefit that you only need one seven-segment driver and as many power transistors as there are displays. Also, as only one display is on at a time, the power consumption is factor of N lower than keeping all the displays on, where N is the number of displays.

The disadvantage is that something (normally your microcontroller) has to keep the displays switching over in concert with the data. If that task gets interrupted by other processing, your display might start doing weird things.

Given these trade-offs, the obvious choice for me was to multiplex the displays. The microcontroller would not be under heavy processing load, the power consumption would be reduced, and I would only need a single 7-segment driver IC and 10 transistors.

Instead, I chose a different approach. I wanted to design a generic seven-segment display (1″ high), so that several of them could be chained together to form a large multi-digit display. I designed a board that was the width and height as the display, so they can just be butted up against one another and soldered together.

Each board has a TLC5916 8-channel constant-current LED driver, enough for the seven segments and the decimal point. The board is designed for common-anode displays. The decimal point in 1″ displays typically only has one LED (the segments have two), but I decided to cheerfully ignore this, especially as for this application there wouldn’t be any decimal points on.

The TLC5916 is essentially an 8-bit shift register and 8-bit latch, with a constant current driver attached to each latch output. The board I designed has:

• A data input (either from a microcontroller or a previous board)
• A data output (from the TLC5916 for driving another board)
• Clock, enable and latch lines that are passed straight through the board, so each TLC5916 shares the same line.
• 5V power for the TLC5916 and the display.

Here are the boards, fresh from OSHPark:

12x bare seven-segment driver boards, still to be cleaned up.

This was my first mistake: the boards are the wrong size. The footprint I used for the seven-segment display was too small. So I had to get them made again. But the circuit itself was fine, so these boards will find a home in a future project.

Lesson 1: Check your boards carefully. (I should already have learnt this lesson)

## Displays #2

After designing the boards, I decided that the best colour for the display would be blue. A UNIX clock should be in blue. It’s a gut instinct. So I went searching for 1″ high blue seven-segment displays and found some in the USA.

There were two problems with this.

Firstly, the pin spacing was slightly different on these displays, which meant I had to force them into the boards with pliers, pray I didn’t break them or the boards.

Secondly, the displays run at an average LED voltage of 6V. The boards only have a 5V supply for the common anode, shared with the TLC5916.

So, I had to modify each board to have both 7 Vand 5V supplies by:

• Making the anode supply 7V.
• Cutting the 5V track to the TLC5916.
• Soldering a 5V regulator upside-down onto the decoupling capacitor for the TLC5916.
• Soldering hook-up wire from the regulator input to the common anode.

The modifications I had to make to each display board

I then bought a cheap DC-DC converter and used it to produce a 7V anode voltage from my 5V supply.

Lesson 2: Specify all components before committing to board fabrication.

Lesson 3: Where components might potentially have different voltages, consider designing for contingency and including jumpers/switches etc.

## Enclosure

I think that this type of project lends itself to see-through casings, so you can look at my shoddy soldering and gluing. So I went with a clear perspex design.

I designed a box in Inkscape, starting with a template from http://boxmaker.rahulbotics.com/, and modifying to suit. I added cutouts for power and time-setting buttons, as well as for each display. I also rounded off the box corners to make the face profile look a little nicer.

The enclosure design was simple enough, but the laser cutting did not go well, and I ended up staying at the hackspace into the early hours of the morning with a scalpel removing bits that didn’t quite cut through.

Lesson 4: Check laser cutter alignment and settings at the extremes of the cutting area.

## Timing and Clock

The clock would probably be unplugged and plugged in again regularly. It’s silly to have to set the time every time this happens, so I got a Chronodot RTC board, which is really just a breakout for a DS3231 RTC chip and backup battery.

This chip stores the date and time (plus alarm settings and control) in 12 8-bit registers, read/writeable over i²c.

I’m quietly building myself an embedded software library, with generic components where possible, feeding into architecture-specifics where necessary. To talk to the DS3231, I therefore needed to write myself an i²c library for the AVR.

All the libraries that already exist for i²c on an AVR use “busy loops” to wait for reception or transmission of a byte. This is absolutely valid software design. The i²c bus is pretty fast, and most applications on an AVR microcontroller will not miss the processor cycles used up in these loops. It also makes control flow simple and code size small.

However, all my other modules for AVR have been interrupt driven, so I rolled by own interrupt-driven state machines for i²c comms. This was entirely unnecessary given the excellent libraries that already exist out there. But then the point of making/hacking is (to one extent or another) doing it yourself. But it did take ages to get all the bugs out. It would have been far quicker if I’d have purchased a simple logic analyser.

Lesson 5: Debugging hardware is less expensive than debugging time.

Having got the i²c comms working, I then implemented a quick pre-build make script to auto-generate a header file containing current time in UNIX format as a define.

By including this header file, I can compare the time from the DS3231 to the compile time. The startup logic is simple:

UNIX Clock Startup Logic

## Setting the Time

Two tactile switches are used to allow the user to set a new time. Ideally the clock would never need changing, since the DS3231 is pretty accurate. But there are two instance where it will:

• During development, when I might write all sorts of stuff to the RTC.
• When leap-seconds are added to the time. If you don’t know about leap-seconds, go read about them. Horology, and the various systems we use to measure time, is pretty fascinating.

One button selects a digit, and one buttons increments that selected digit.

To read the buttons, I wrote a simple library that:

• Debounces button inputs with a variable time.
• Will call a per-button callback function on button down, button up, and at a varying rate while held down.

The library is entirely architecture independent, and relies on regular updates from a button reading task or interrupt. This was the only bit of the project that just worked.

Lesson 6: Simple software libraries are good for the soul.

## Code Design

All my projects have an interrupt driven state machine at their core, and this was no exception. The logic for this one is very simple, and acts just to prevent the clock from updating while the buttons are being used:

The mains state machine for the UNIX Clock

## Hardware

Because I wanted this to be a quick and simple project, I didn’t bother designing a PCB. I thought it would be easier to just wire together pre-built boards. I was wrong.

There are four separate boards in the design (counting all the display boards as one), plus two buttons, plus the little DC-DC converter I had to buy. That’s a lot of point-to-point wiring. It looks ugly, takes up space and has many potential failure points.

Lesson 7: Sometimes rolling your own IS the right way to go.

## To Conclude

It all worked out OK in the end. I had a few frustrating nights where I couldn’t figure out what was going wrong with my time conversions, which turned out to be a 16-bit truncation of a 32-bit number. I’d tested this particular library on my PC, where it worked fine. On the AVR, not so much.

Lesson 8: PC test rigs are great. Test driven development is great. But remember to account for differences between your 32/64-bit PC and your tiny 8-bit microcontroller.

Here are some photos of the finished article:

The clock hardware, with all the messy point-to-point wiring.

The clock on display at Nottingham Hackspace. The time is 20:03:33GMT on Friday 25th October 2013.

Posted in Uncategorized | 6 Comments

# LED Auto-Dimming

This is the last post in a series of four on the days-accident-free counter I made for Nottingham Hackspace. You can read the other three here:

The electronics for the counting of days and digit display was relatively simple. I wanted to make something a bit more complicated as well.

I decided it would be a good idea to have the LEDs auto-dimming with the ambient light level. There are many sensible ways to achieve this:

• Using an LDR to control the duty cycle of a 555 timer producing PWM.
• Using an LDR to directly control the LED current via a transistor.
• Using an LDR to measure the light level via a microcontroller and output PWM from that.

What isn’t sensible is to re-create an “output-compare” timer entirely in logic in order to produce PWM. But that’s what happened.

My starting point was to produce an 8-bit timer. A 555 timer produces a 36kHz clock that feeds a 12-bit 4040 counter. The 9th bit of this counter is used as a “period complete” signal. The PWM frequency is 36kHz/256 = 140Hz.

An LDR is read by a ADC0820 IC, which is a single-channel ADC designed with 8-bit parallel output designed for input to a microcontroller, before the days of high-level integration and high-speed serial made such things redundant. This IC has a RD pin which starts a conversion when bought LOW, and an INT output that goes LOW when conversion is complete. There are also a few other control pins  (MODE/CS/OFL) that were tied low as I didn’t need them.

The 8-bit output of the ADC and the 8-bit timer output feed a 74688 8-bit comparator, which has an output that goes LOW when it’s two inputs are equal. Therefore, given a free-running clock and a static ADC input, the comparator will output LOW for a single clock period. This timer operation is pretty much how PWM is produced by a microcontroller: a free-running counter and a compare register.

The ADC and timer need some synchronising around the clock rollover. A few logic gates are used to glue together the ADC and timing signals. I needed a NOT and an AND, these can be produced by three NAND gates, so I could use a single 4011 quad NAND chip.

Hopefully these timing and logic diagrams will make it clearer.

So, the counter counts to 256, which clears the ADC read signal (HIGH). On count 257, the time reset output (via NAND gates) goes high, which sets the count to 0. This sets the ADC read signal (LOW), and a new conversion is performed. At end-of-conversion, the INT signal sets the LED flip-flop (via another NAND gate)

The comparator output was clears the LED flip-flop at a point in the cycle corresponding to the light level. In this way, light-dependant duty cycle PWM is produced. The PWM feeds a power transistor output stage for actually driving the LEDs.

So, that’s how you over-engineer an auto-dimming circuit. Never actually do this.

Finally, here’s the PCB with all the components mounted. The LDR plugs in next to the potentiometer, which is used with the LDR to form a potential divider.

Posted in Electronics | Tagged , , | 4 Comments