近来在研究条码的实现,遇到一些坑,现在把自己遇到的一些情况分享一下。
世界上约有225种以上的条形码,一般较流行的有 39码、EAN码、UPC 码、128码,以及专门用於书刊管理的ISBN、ISSN等。
![](https://img-blog.csdnimg.cn/20201210190608782.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2ZlaWxpYW5neXk=,size_16,color_FFFFFF,t_70)
我们先从Code39码开始:
39码具有以下特性:
条码的长度没有限制,可随着需求作弹性调整。但在规划长度的大小时,应考虑条码阅读机所能允许的范围,避免扫瞄时无法读取完整的资料。
起始码和终止码必须固定为“ * ”字元。允许条码扫瞄器进行双向的扫瞄处理。由於39码具有自我检查能力,故检查码可有可无,不一定要设定。 条码占用的空间较大。
可表示的资料包含有:0~9的数字,A~Z的英文字母,以及“+”、“-”、“*”、“/”、“%”、“$”、“.”等特殊符号,再加上空白字元“ ”,共计44组编码,并可组合出128个ASCII CODE的字元符号,如表所示。
表 ASCII CODE字元符号与39码对照表
![](https://img-blog.csdnimg.cn/20201210190653577.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2ZlaWxpYW5neXk=,size_16,color_FFFFFF,t_70)
这里就只研究0~9的数字,A~Z的英文字母,以及“+”、“-”、“*”、“/”、“%”、“$”、“.”等特殊符号,再加上空白字元“ ”,这44组编码,其他ASCII码的组合暂时不考虑;
CODE 39码的编码规则是:
1、9条线表示一个字符;
2、黑线表示1,空线表示0;
3、线宽的表示w,窄的表示n;
4、条形码的首尾各一个*标识开始和结束;
5、宽条和窄条的比率为2-3之间;
6、字符和字符之间的有空白间隔;
7、校验位可不做编码;
编码对映表如下:
字元 |
逻辑型态 |
|
字元 |
逻辑型态 |
|
A |
110101001011 |
wnnnnwnnwn |
N |
101011010011 |
nnnnwnnwwn |
B |
101101001011 |
nnwnnwnnwn |
O |
110101101001 |
wnnnwnnwnn |
C |
110110100101 |
wnwnnwnnnn |
P |
101101101001 |
nnwnwnnwnn |
D |
101011001011 |
nnnnwwnnwn |
Q |
101010110011 |
nnnnnnwwwn |
E |
110101100101 |
wnnnwwnnnn |
R |
110101011001 |
wnnnnnwwnn |
F |
101101100101 |
nnwnwwnnnn |
S |
101101011001 |
nnwnnnwwnn |
G |
101010011011 |
nnnnnwwnwn |
T |
101011011001 |
nnnnwnwwnn |
H |
110101001101 |
wnnnnwwnnn |
U |
110010101011 |
wwnnnnnnwn |
I |
101101001101 |
nnwnnwwnnn |
V |
100110101011 |
nwwnnnnnwn |
J |
101011001101 |
nnnnwwwnnn |
W |
110011010101 |
wwwnnnnnnn |
K |
110101010011 |
wnnnnnnwwn |
X |
100101101011 |
nwnnwnnnwn |
L |
101101010011 |
nnwnnnnwwn |
Y |
110010110101 |
wwnnwnnnnn |
M |
110110101001 |
wnwnnnnwnn |
Z |
100110110101 |
nwwnwnnnnn |
|
|
|
|
|
|
|
|
|
|
|
|
0 |
101001101101 |
nnnwwnwnnn |
+ |
100101001001 |
nwnnnwnwnn |
1 |
110100101011 |
wnnwnnnnwn |
- |
100101011011 |
nwnnnnwnwn |
2 |
101100101011 |
nnwwnnnnwn |
* |
100101101101 |
nwnnwnwnnn |
3 |
110110010101 |
wnwwnnnnnn |
/ |
100100101001 |
nwnwnnnwnn |
4 |
101001101011 |
nnnwwnnnwn |
% |
101001001001 |
nnnwnwnwnn |
5 |
110100110101 |
wnnwwnnnnn |
$ |
100100100101 |
nwnwnwnnnn |
6 |
101100110101 |
nnwwwnnnnn |
. |
110010101101 |
wwnnnnwnnn |
7 |
101001011011 |
nnnwnnwnwn |
空白 |
100110101101 |
nwwnnnwnnn |
8 |
110100101101 |
wnnwnnwnnn |
|
|
9 |
101100101101 |
nnwwnnwnnn |
|
|
|
这里的逻辑形态,并不包括每个字符之间的空白间隙,所以在编码的时候要再加一个0,很多资料上都未提醒着一点,注意别踩坑。
现在直接上代码:
#include <stdio.h>
#include <string.h>
#include <CODE39.h>
#include "lcd.h"
//ÿ����ʾ�ַ���Ӧ������
const char *Code39DataBuf[43]= {
//ÿ����Ԫ���������9������ɣ��ַ����ַ�֮��Ŀհ��������ÿһ������0���ǿհ�϶
//1�ú�ɫ�߱����0�ð�ɫ�߱��
// ����̬ //��Ԫ ACSII(DEC)
"1010011011010",// 0 48
"1101001010110",// 1 49
"1011001010110",// 2 50
"1101100101010",// 3 51
"1010011010110",// 4 52
"1101001101010",// 5 53
"1011001101010",// 6 54
"1010010110110",// 7 55
"1101001011010",// 8 56
"1011001011010",// 9 57
"1101010010110",// A 65
"1011010010110",// B 66
"1101101001010",// C 67
"1010110010110",// D 68
"1101011001010",// E 69
"1011011001010",// F 70
"1010100110110",// G 71
"1101010011010",// H 72
"1011010011010",// I 73
"1010110011010",// J 74
"1101010100110",// K 75
"1011010100110",// L 76
"1101101010010",// M 77
"1010110100110",// N 78
"1101011010010",// O 79
"1011011010010",// P 80
"1010101100110",// Q 81
"1101010110010",// R 82
"1011010110010",// S 83
"1010110110010",// T 84
"1100101010110",// U 85
"1001101010110",// V 86
"1100110101010",// W 87
"1001011010110",// X 88
"1100101101010",// Y 89
"1001101101010",// Z 90
"1001010110110",// - 45
"1100101011010",// . 46
"1001101011010",// sp 32
"1001001001010",// $ 36
"1001001010010",// / 47
"1001010010010",// + 43
"1010010010010",// % 37
};
char *code39_Code(char *CharToShow, u8 len)
{
//PixelPtr�Ǻ������ص��ָ��
// char *PixelPtr;
u8 lcd_id[12]; //���LCD ID�ַ���
static char PixelPtr[520];
uint8_t i,j,CheakID;
uint32_t CheakSum = 0;
const char *Space_CODE39 = "000000000";
const char *BStartEndBuf = "1001011011010"; // *
//����У��λ
for(i=0; i<len; i++)
{
if((CharToShow[i]>='0') && (CharToShow[i]<='9')) CheakSum+=((CharToShow[i]-'0'));//0~9
else if((CharToShow[i]>='A') && (CharToShow[i]<='Z')) CheakSum+=((CharToShow[i]-'0')-7);//A~Z
else if(CharToShow[i]=='-') CheakSum+=36;
else if(CharToShow[i]=='.') CheakSum+=37;
else if(CharToShow[i]==' ') CheakSum+=38;
else if(CharToShow[i]=='&') CheakSum+=39;
else if(CharToShow[i]=='/') CheakSum+=40;
else if(CharToShow[i]=='+') CheakSum+=41;
else if(CharToShow[i]=='%') CheakSum+=42;
}
CheakID = CheakSum%43;
sprintf((char*)lcd_id,"LCD ID:%d",CheakID);//
LCD_ShowString(30,40,210,24,24,lcd_id);
//�����ǿհ�����9�����صĿհ�
strcat(PixelPtr, Space_CODE39);
//��������ʼ�ַ�*
strcat(PixelPtr, BStartEndBuf);
for (int i = 0; i < len; i++)
{//
if((CharToShow[i]>='0') && (CharToShow[i]<='9')) strcat(PixelPtr, Code39DataBuf[(CharToShow[i]-'0')]);//0~9
else if((CharToShow[i]>='A') && (CharToShow[i]<='Z')) strcat(PixelPtr, Code39DataBuf[(CharToShow[i]-'0')-7]);//A~Z
else if(CharToShow[i]=='-') strcat(PixelPtr, Code39DataBuf[36]);//
else if(CharToShow[i]=='.') strcat(PixelPtr, Code39DataBuf[37]);//
else if(CharToShow[i]==' ') strcat(PixelPtr, Code39DataBuf[38]);//
else if(CharToShow[i]=='&') strcat(PixelPtr, Code39DataBuf[39]);//
else if(CharToShow[i]=='/') strcat(PixelPtr, Code39DataBuf[40]);//
else if(CharToShow[i]=='+') strcat(PixelPtr, Code39DataBuf[41]);//
else if(CharToShow[i]=='%') strcat(PixelPtr, Code39DataBuf[42]);//
}
//��
// strcat(PixelPtr,Code39DataBuf[CheakID]);
//�����ǽ����ַ�*
strcat(PixelPtr, BStartEndBuf);
return PixelPtr;
}
int CODE39_DISPLAY( char *CODE39_data , u8 len)
{
u16 i,j,k;
u16 x,y,p;
char *code;
code = code39_Code(CODE39_data,len);
p = (3-1)*2;//���С
x = 24;
y = 80;
for(i=0;i<strlen(code);i++)//width
{
k=41;//height
for(j=0;j<k;j++)
{
if(code[i]>'0')
{
LCD_Fill(x+p*i,y+p*j,x+p*(i+1)-1,y+p*(j+1)-1,BLACK);
}
else
{
}
}
}
}