Code 39 - A Gentle Introduction: The Classic Barcode That Started It All |
Subtitle: A Deep Dive into the Symbology, Its Encoding Rules, Its Decoding Algorithm, and Its Real-World Implementations - with Examples from Symbol, Zebra, Honeywell, Datalogic, Microchip, and NXP |

|
Opening Summary |
Before the Universal Product Code (UPC) became ubiquitous in retail, before Code 128 packed more data into a smaller space, there was Code 39. Developed in 1974 by David Allais and Ray Stevens of Intermec, Code 39 is one of the oldest and simplest barcode symbologies. It is still widely used today in logistics, manufacturing, defense, and healthcare, where its robustness, variable length, and alphanumeric capability make it a versatile workhorse. Its encoding is straightforward: each character is represented by a pattern of five bars and four spaces, with three of the nine elements being wide and six being narrow. |
This article is dedicated to Code 39 - the gentle introduction to barcode decoding. We will explore its history, its encoding rules, and its decoding algorithm. We will examine the start and stop characters, the checksum (optional but recommended), and the quiet zone requirements. We will look at how major companies have implemented Code 39 decoding in their products. We will see how Symbol (now Zebra) supported Code 39 in the LS2208. We will explore Honeywell's implementation of Code 39 in their imagers. We will examine Datalogic's support for Code 39 in their industrial scanners. We will also look at reference designs from Microchip, NXP, and STMicroelectronics, which include complete Code 39 decoding examples. |
By the end of this journey, you will understand that Code 39 is not just a historical curiosity but a robust and practical symbology that continues to play a vital role in automatic identification. You will see how its simple encoding rules make it an ideal starting point for learning barcode decoding. |

|
Full Article |
Section 1: The Origins of Code 39 - A Response to the Need for Alphanumeric Codes |
In the early 1970s, the retail industry was developing the UPC, which was a numeric-only, fixed-length code. But the military, automotive, and healthcare industries needed a code that could encode letters, numbers, and a few special characters, and that could be variable in length. Intermec responded to this need by developing Code 39 in 1974. The name '39' comes from the fact that the original code could encode 39 characters: 0-9, A-Z, and a few special characters (space, -, ., $, /, +, %). (Later, an extended version, Code 39 Full ASCII, was developed to encode all 128 ASCII characters.) |
Code 39 was designed to be easy to print and easy to decode. It uses a self-checking encoding: each character has a unique pattern of bars and spaces, and the pattern is designed to be robust to printing and scanning errors. The start and stop characters are the same (an asterisk), which makes the code bidirectional. |
Section 2: The Encoding Structure - Five Bars and Four Spaces |
Each Code 39 character is represented by a pattern of nine elements: five bars (dark) and four spaces (light), alternating. The pattern always starts and ends with a bar. Each element is either 'wide' or 'narrow.' A narrow element is one module wide; a wide element is two or three modules wide. The exact width ratio depends on the print quality standard. The ratio is typically 2.2:1 to 3:1 (wide to narrow). |
The pattern has exactly three wide elements out of the nine. The three wide elements can be bars or spaces. The pattern is chosen so that no two characters are identical, and the code is self-checking. |

|
Section 3: The Encoding Alphabet - The 39 Characters |
The original Code 39 alphabet includes 39 characters: |
- Digits: 0 to 9 |
- Uppercase letters: A to Z |
- Special characters: space, -, ., $, /, +, % |
Each character is assigned a unique 9-element pattern. The patterns are defined in the Code 39 specification. |
Section 4: The Start and Stop Characters - The Asterisk |
The start and stop characters are both the asterisk (*). The asterisk is encoded as a specific 9-element pattern (a wide bar, narrow bar, wide space, narrow bar, narrow space, wide bar, narrow space, narrow bar, wide space). The same pattern is used for both the start and stop characters. |
The use of the same character for start and stop makes Code 39 bidirectional. The decoder can read the barcode from left to right or from right to left. |

|
Section 5: The Quiet Zone - The White Margin |
Code 39 requires a quiet zone on both sides of the barcode. The quiet zone is a white margin that is at least 10 times the module width. The quiet zone is used by the decoder to detect the barcode's presence and to reset its timing. |
The quiet zone is essential for reliable decoding. |
Section 6: The Checksum - The Optional Modulo 43 Check |
Code 39 has an optional checksum. The checksum is a modulo 43 calculation. The checksum character is appended to the data characters. The checksum is used to verify the integrity of the decoded data. |
The checksum is not mandatory, but it is highly recommended, especially in applications where data integrity is critical. |

|
Section 7: The Checksum Calculation - A Weighted Sum |
The checksum is calculated by assigning a value to each character. The digits 0-9 are assigned the values 0-9. The letters A-Z are assigned the values 10-35. The special characters are assigned values 36-42. |
The checksum is the sum of all the character values, modulo 43. The resulting value is converted back to a character using the same value table. |
Section 8: The Decoding Process - An Overview |
The decoding process for Code 39 consists of several steps: |
1. Capture the Edge Timings: The timer capture module measures the pulse widths of the digitised waveform. |
2. Estimate the Module Width: The decoder estimates the module width using the shortest pulse method, the histogram method, or the running-average method. |
3. Normalize the Pulse Widths: The decoder divides each pulse width by the module width and rounds to the nearest integer (1 for narrow, 2 or 3 for wide). |
4. Find the Quiet Zone: The decoder finds the quiet zone before and after the barcode. |
5. Find the Start and Stop Characters: The decoder finds the start and stop characters (the asterisk pattern). |
6. Extract the Data Characters: The decoder extracts the data characters between the start and stop characters. |
7. Decode Each Character: The decoder compares the pattern of wide and narrow elements to the lookup table to find the character. |
8. Verify the Checksum (if present): The decoder calculates the checksum and compares it to the checksum character. |
9. Output the Data: The decoder outputs the decoded data. |

|
Section 9: Finding the Start and Stop Characters - The Asterisk Pattern |
The decoder finds the start and stop characters by looking for the asterisk pattern. The asterisk pattern is a specific sequence of wide and narrow elements. The decoder scans the element sequence for a pattern that matches the asterisk pattern. |
The asterisk pattern is unique. It is the only pattern that has the specific combination of wide and narrow elements. |
Section 10: Extracting the Data Characters - Between the Start and Stop |
Once the start character has been found, the decoder extracts the data characters between the start and stop characters. The data characters are groups of 9 elements (5 bars and 4 spaces). |
The decoder groups the elements into 9-element patterns. Each pattern corresponds to a character. |

|
Section 11: Decoding Each Character - A Lookup Table |
The decoder decodes each character by comparing its 9-element pattern to a lookup table. The lookup table contains the patterns for all 39 characters. The decoder finds the matching pattern and outputs the corresponding character. |
The lookup table is stored in the microcontroller's program memory. |
Section 12: Symbol's LS2208 - Code 39 Support |
Symbol's LS2208 supports Code 39 decoding. The LS2208's firmware includes the Code 39 decoder. The decoder uses the shortest pulse method to estimate the module width. The decoder includes the optional checksum verification. |
The LS2208's Code 39 decoder is robust and reliable. It has been tested with millions of Code 39 barcodes. |

|
Section 13: Honeywell's Code 39 Implementation |
Honeywell's imagers support Code 39 decoding. The imagers use a histogram-based method to estimate the module width. The histogram-based method provides better accuracy and robustness than the shortest pulse method. |
Honeywell's Code 39 decoder also includes the optional checksum verification. The decoder is part of Honeywell's Adaptus firmware. |
Section 14: Datalogic's Code 39 Implementation |
Datalogic's industrial scanners support Code 39 decoding. The scanners use a running-average method to estimate the module width. The running-average method adapts to speed changes during the scan. |
Datalogic's Code 39 decoder also includes the optional checksum verification. The decoder is part of Datalogic's Auto-Adaptive Decoding technology. |

|
Section 15: The Code 39 Lookup Table - A Memory of Patterns |
The Code 39 lookup table is a memory that stores the 9-element patterns for each character. The lookup table is specific to Code 39. The lookup table is stored in the microcontroller's program memory. |
The lookup table is a critical part of the Code 39 decoder. |
Section 16: The Code 39 Start/Stop Character - The Unique Asterisk |
The asterisk pattern is unique to the start and stop characters. The asterisk pattern is not used for any data character. This makes it easy for the decoder to find the start and stop characters. |
The asterisk pattern is: wide bar, narrow bar, wide space, narrow bar, narrow space, wide bar, narrow space, narrow bar, wide space. |

|
Section 17: The Code 39 Quiet Zone - A Minimum Requirement |
Code 39 requires a quiet zone of at least 10 modules on each side of the barcode. The quiet zone is essential for reliable decoding. The decoder uses the quiet zone to detect the barcode's presence and to reset its timing. |
Section 18: The Code 39 Checksum - An Optional Verification |
The Code 39 checksum is an optional verification. The checksum is a modulo 43 calculation. The checksum character is appended to the data characters. The decoder verifies the checksum to ensure the data's integrity. |

|
Section 19: The Code 39 Checksum Calculation - A Detailed Example |
The checksum is calculated by assigning a value to each character. The digits 0-9 are assigned values 0-9. The letters A-Z are assigned values 10-35. The special characters are assigned values 36-42. The checksum is the sum of all character values, modulo 43. The result is converted back to a character. |
Section 20: The Code 39 Decoder's Tolerance - Handling Variations |
The Code 39 decoder has a tolerance for variations in the pulse widths. The tolerance accounts for scanning speed variations, print quality variations, and noise. The tolerance is typically 20-25%. |
The tolerance ensures that the decoder can handle variations in the barcode's quality. |

|
Section 21: The Code 39 Decoder and the Noise |
The Code 39 decoder is robust to noise. The decoder's tolerance helps to mitigate the effects of noise. The decoder also uses the checksum to detect and reject erroneous data. |
Section 22: The Code 39 Decoder and the Jitter |
The Code 39 decoder is robust to jitter. The decoder's tolerance helps to mitigate the effects of jitter. |

|
Section 23: The Code 39 Decoder and the Distortion |
The Code 39 decoder is robust to distortion. The decoder's tolerance helps to mitigate the effects of distortion. |
Section 24: The Code 39 Decoder and the Scanning Speed |
The Code 39 decoder is robust to scanning speed variations. The module width estimation algorithm handles the variations in scanning speed. |
Section 25: The Code 39 Decoder and the Print Quality |
The Code 39 decoder is robust to print quality variations. The module width estimation algorithm handles the variations in print quality. |

|
Section 26: The Code 39 Decoder and the Symbology |
The Code 39 decoder is specific to Code 39. The decoder uses the Code 39 encoding rules and the Code 39 lookup table. |
Section 27: The Code 39 Decoder and the Start/Stop Characters |
The Code 39 decoder uses the start and stop characters to locate the barcode and to determine the symbology. |
Section 28: The Code 39 Decoder and the Quiet Zone |
The Code 39 decoder uses the quiet zone to detect the barcode's presence and to reset its timing. |

|
Section 29: The Code 39 Decoder and the Checksum |
The Code 39 decoder optionally verifies the checksum. The checksum verification ensures the data's integrity. |
Section 30: The Code 39 Decoder in Microchip's Reference Design |
Microchip's reference design includes a complete Code 39 decoder. The decoder uses the shortest pulse method to estimate the module width. The decoder includes the optional checksum verification. |
Section 31: The Code 39 Decoder in NXP's Reference Design |
NXP's reference design includes a Code 39 decoder. The decoder uses a histogram-based method to estimate the module width. The decoder includes the optional checksum verification. |

|
Section 32: The Code 39 Decoder in STMicroelectronics' Reference Design |
STMicroelectronics' reference design includes a Code 39 decoder. The decoder uses the shortest pulse method to estimate the module width. The decoder includes the optional checksum verification. |
Section 33: Code 39 vs. Other Symbologies - A Comparison |
Code 39 is a simple and robust symbology, but it is not as dense as some newer symbologies. Code 39 uses 9 elements per character, which is more than Code 128 (6 elements per character) or UPC (7 elements per digit). Code 39 is also limited to uppercase letters, digits, and a few special characters (in its original version). |
However, Code 39 is easy to print and easy to decode. It is still widely used in applications where data density is not a critical issue. |
Section 34: Code 39 Full ASCII - An Extension |
Code 39 Full ASCII is an extension of Code 39 that can encode all 128 ASCII characters. It uses pairs of characters to represent the full ASCII set. The decoder must handle the extended character set. |

|
Section 35: The Future of Code 39 - Still Going Strong |
Code 39 is still going strong after over 50 years. It is a testament to the robustness and simplicity of its design. Code 39 will continue to be used in many applications for years to come. |
Section 36: Code 39 - A Summary of Best Practices |
Based on our exploration, let us summarize the best practices for implementing Code 39 decoding in a barcode scanner: |
1. Understand the Encoding Rules: The five bars and four spaces, three wide elements. |
2. Use a Robust Module Width Estimation: Use the histogram-based method for better accuracy. |
3. Implement a Lookup Table: The lookup table is the key to fast decoding. |
4. Include Checksum Verification: The checksum ensures data integrity. |
5. Provide Tolerance: The decoder must tolerate variations in the pulse widths. |
6. Test the Decoder: The Code 39 decoder must be tested with a variety of barcodes, under a variety of conditions. |

|
Final Summary |
Code 39 is the gentle introduction to barcode decoding. It is a simple, robust, and versatile symbology that has been in use for over 50 years. Each character is represented by a pattern of five bars and four spaces, with three wide elements. The start and stop characters are the asterisk. The optional checksum provides data integrity. |
We have seen how major companies have implemented Code 39 decoding in their products. Symbol's LS2208 supports Code 39. Honeywell's imagers include a Code 39 decoder. Datalogic's industrial scanners support Code 39. Microchip, NXP, and STMicroelectronics provide reference designs with complete Code 39 decoders. |
Code 39 is a classic symbology that continues to play a vital role in automatic identification. Its simple encoding rules make it an ideal starting point for learning barcode decoding. |