Barcode Reading Basics

This page was originally rescued from http://www.dvanhorn.org/Barcode/Basics.php which has been taken down.

There are a few basics you need in order to get started.

1: You need to have an interrupt on each edge of the light pen input. This interrupt will capture a timer value to memory, reset the timer, and then disable the current edge, and enable the opposite edge. (IOW, if this was a falling edge transition, then we disable ints on the falling edge, and enable rising edge int)

2: You need at least an 8 bit timer, running at roughly 20kHz. Faster is better, but may overflow the 8 bit counter at low scan speeds. At high scan speeds, you will hit granularity problems when the narrowest element becomes smaller than about 8 clocks. If you do "post process", then the overflow of the timer (no edge within 255 clocks) is your signal that the scan has ended.

3: You need some storage space for timing values. There are two approaches here, "on-the-fly" and "post-process". Post is the easiest, but since it stores up all the samples before processing them, it eats a fair sized buffer in ram. "on-the-fly" requires only about 10 bytes of ram for the timing samples. Both versions will need storage for 13 digits, or 15/18 if you also read supplementals.

The total amount of ram that you'll need is somewhat variable. In the post process approach, you also need to store the "noise" bits that you'll get as the pen approaches the target and as it leaves the target.

4: A way to create repeatable scans. If you are working in the AVR platform, with the Atmel tools, then you're in luck, this really isn't too hard, and can be done in simulation.

5: You need to understand how a light pen works. You get a logic 1 or logic 0, depending on wether the pen sees "bright" or "dark". Different pens may output a different state for "bright", so watch out. Also, pens usually need a few transitions from dark to bright to calibrate their level-slicers. This means that the first couple timings you get may be somewhat distorted. Another note, for several reasons, dark elements appear wider than they really are, and bright elements appear thinner than they really are. This is usually a trivial effect, but it's worth compensating for.

Assuming you're working on the AVR 8515:

Connect the light pen to INT1 (Port D bit 3):

Set up interrupts: This is a little tricky, you'll need to set the interrupt state at the beginning to interrupt on "dark" output from the pen. Every time the int occurs, you'll change the edge trigger to the opposite edge.

Set timer 0 to run at 20kHz:

Set a memory buffer to store timing values:

Create an ISR that toggles the pen input interrupt edge on each pen interrupt, captures the timer value, resets the timer to zero, and stores the timer value in the timing buffer.

Create a timing buffer dump routine, that outputs the timing buffer in the format of an assembler table

I won't detail all this here, but what you need is a simple routine, triggered by the end of the read, to output each byte in the timing buffer, with a preceeding "$" and trailing "," ($01,$02,...) and finish the string with a CR/LF pair.

Also, at the beginning of the scan, you need to output what you thought the barcode was. This will make it easier for you to debug the code.

The end product of all this should be a line that looks like this:

0123456789010<spc>$01,$13,$15,........$22<CR><LF>

You'll use a terminal program to capture these lines into a file. Then, using a text editor, delete all (any?) lines where you read the code properly, and save the ones where you had errors. After you do this a few times, it will become a tedious process of deleting all the correct reads, to find the one or two you missed, and pretty soon, you will be into torturing the reader to see if you can make it miss.. :)

This file is then included in the assembly, with all but one scan commented out.

This scan is then read into ram, and the recognition process run in the AVR simulator, so you can step through it and watch where it fails.

Do while not reading perfectly:

If you can decode it manually by looking at the timing samples, then figure out why your code can't, and fix that.

End while

Seriously, it is fairly easy to get to the point where you are reading codes that are distorted right up to the theoretical limit. In UPC/EAN this is a bar or space distorted to X.5 modules, so that it is impossible to know whether it was supposed to be X or X+1 modules wide. The granularity of your timer becomes a factor here, faster is better. This may force you into 16 bit samples if you want to get the last little drip of performance. In my experience, this is not necessary though. By the time you are out of range in an 8 bit counter, you are dealing with codes distorted far beyond the spec.