Scanning
There are a number of parameters that must be considered when specifying
the optical characteristics of a barcode scanner. Briefly, the optical
wavelength can be centered in the visible red or infra-red spectrum.
The advantage of using the visible spectrum is that if the barcode label
looks okay to you it should appear likewise to the scanner.
Figure 1 - The X Dimension
The other thing you should be concerned with is the scanner's optical
aperture size. A small spot size responds accurately to bar edges, but
also picks up small spots and voids. Conversely, if the spot size is larger
than the smallest bar/space element (the X dimension) then the scanner
will have difficulty resolving the pattern. An aperture size about .8X
works well for most codes. Standardization limits the number of choices
to either high resolution (6 mil) or low resolution (10 mil).
Listing 1 - Barcode sample/decode structure
struct BC_STRUCT{
unsigned short sample_buffer[300];
unsigned short sample_ptr;
unsigned short sample_ctr;
unsigned char overflow_ctr;
unsigned char sample_state;
#define WAITING 0
#define BUSY 1
#define READY 2
unsigned char decode_buffer[48];
unsigned char decode_count; };
Sampling
To decode a barcode you need to collect timing information for all the
bar/space elements of the symbol. To do this the first step is to scan
the barcode, either physically (moving barcode or moving scanner) or
electrically (CCD). As the barcode is being scanned the scanner converts
the optical pattern into an electrical pattern, which is fed into a processor.
The processor measures the width of the individual bars and spaces and
stores the resulting counts in a buffer for processing by the decode
routine.
You also need a means of determining when sampling is complete, which is
accomplished with an overflow timer. Every time a sample is received, the
sample routine re-arms the timer. When the scanner stops delivering sample
data the timer is no longer refreshed and eventually overflows signaling
that sampling has concluded.
The very simplest sampling implementation requires the processor to suspend
all other operations and dedicate itself exclusively to the task of sampling
barcode data. The actual timing measurements can be performed using a rudimentary
counting loop in software. If the system has a hardware timer, it can be
leveraging in lieu of the counting loop, usually providing better accuracy
and greater resolution.
Most applications will sample under interrupts, utilizing a hardware timer.
You must provide a means of generating an interrupt on each bar/space transition
which might involve nothing more than properly configuring the interrupt
controller or may require additional external circuitry, depending on the
processor. Every time an interrupt occurs, the timer is stopped, read,
and re-loaded. For this approach to work the processor must possess a fast,
deterministic interrupt controller since the accuracy of the measurements
depend on the interrupt response time and, more importantly, on the variations
in interrupt response time.
Better results can be obtained with the aid of a timer capture system.
In such a system the measurement count is copied into a capture register
from a free-running timer without stopping the timer. This happens automatically
in hardware under control of a pin that can also be used to assert an interrupt
when the capture occurs. This decouples the measurement accuracy from the
interrupt system performance since the processor has until the next transition
to read the captured count before it's overwritten. Very accurate timing
measurements can be achieved this way and it's easy to support multiple
barcode channels simultaneously using this method.
Listing 2 - General Purpose Barcode Sampling
// Sampling
void barcodeSample(struct bc_struct *p, unsigned int count){
if(p->sample_state == READY){
return;
}
p->overflow_ctr = BARCODE_OVERFLOW_TIME;
if(p->sample_state != BUSY){
p->sample_ctr = 0; p->sample_ptr = p->sample_buffer;
p->sample_state = BUSY; return;
}
if(p->sample_ctr++ >= (sizeof p->sample_buffer / 2) - 1){
p->sample_ctr = 0;
p->overflow_ctr = 1; return;
}
*p->sample_ptr++ = count;
}
// Sample overflow
void barcodeOverflow(struct bc_struct *p){
*p->sample_ptr++ = 0;
p->sample_state = READY;
}
Sampling Routine
Listing 2 is a hardware-independent sample routine that can support multiple
barcode scanners. The input arguments include a pointer to a barcode structure
and the sample count itself; the calling function deals with the underlying
hardware that generates the count. The routine maintains the sample state
using the sample_state member of the barcode structure. The routine first
checks that sample_state is not READY, indicating a set of sample buffer
is available and hasn't been processed yet, reloads the overflow timer,
then looks at sample_state to determine if this is the first sample or
if sampling is already in progress. If it's the first sample then the next
few lines initialize the sample counter and pointer and set sample_state
to BUSY indicating that the first sample has been processed. If sample_state
is BUSY, indicating that sampling is already in progress, the routine store
the count if the sample buffer has enough space.
Sample overflow is handled by the overflow routine, which appends a NUL
count to the sample buffer to denote the end of the colleted samples and
sets sample_state to READY. The READY sample_state has the dual function
of informing the process code that it can attempt to decode the sample
buffer and also prevents the sample routine from collecting any additional
data, which would corrupt the buffer. The process code clears the READY
sample_state once it's done processing the sample buffer, freeing the sample
routine to to collect new sample data. The overflow routine can be invoked
from some general time keeping code or from a timer interrupt.
One other thing to keep in mind is that most barcode scanners exhibit a
timing distortion on the first bar since it takes a finite amount of time
for the scanner's analog wave shaper to establish its internal reference.
Generally, the distortion affects the first several samples but the problem
is most pronounced on the first. Depending on the scanner it may be necessary
to reconstruct the first sample. The simplest tactic is to replace the
first sample with what the particular decode routine is expecting for a
given symbology; either a narrow or a wide. There are more sophisticated
ways to discern the value of the first sample but they require a knowledge
of the specific electrical performance characteristics of the scanner.
Also, the absolute scan velocity might have an impact on the amount of
distortion.