C 64
Anwendung des Monats

Bar-Codes selbst gemacht

Jeder kennt sie, aber die wenigsten wissen über sie Bescheid. Gemeint sind die Strich-Codes auf Milchtüten, Waschpulvern und anderen Konsumgütern. Daß man diese Codes mit einem C 64 und einem Epson-Drucker selbst herstellen kann, zeigt unsere Anwendung des Monats.

Lebensmittelverpackungen, Dose, Glas und Seife mit Strichcodes vor blauem Hintergrund
Sie sind überall, die dünnen schwarzen Striche, deren genaue Bedeutung nur die Computer kennen.
Strichcode mit den Ziffern 4026 und 6305 darunter

Um ein großes Wagenlager effektiv verwalten zu können, ist ein hohes Maß an Genauigkeit und Schnelligkeit erforderlich. Der aktuelle Warenbestand muß ständig abrufbar sein, damit zum Beispiel eventuell erforderliche Nachbestellungen rechtzeitig erkannt und ausgeführt werden können.

Dieser enorme Verwaltungsaufwand erfordert ein hohes Maß an Geschwindigkeit und Verläßlichkeit. Eine optimale Aufgabe für einen Computer.

Das Problem besteht nun darin, dem Computer die Artikelnummer einzugeben. Unsere arabischen Zahlen sind nämlich für eine schnelle Auswertung durch ein Lesegerät zu komplex, zu fehleranfällig und daher ungeeignet. Dadurch kam man auf das Prinzip der sogenannten »Bar-Codes«: Sie entsprechen dem einzigen, für Computer verständlichen Zahlensystem (Binärsystem), bestehend aus Nullen und Einsen. Da sich zwei Werte durch zwei Zustände unterscheiden lassen, genügt die Darstellung »Strich« oder »nicht Strich«. Somit kann jedem Artikel entsprechend seiner Lagernummer eine Kombination aus »Strich« und »nicht Strich« zugeordnet werden. Der Lagerverwalter braucht beim Warenein- und -ausgang nur noch mit einem Lesestift über den Bar-Code-Aufkleber der Packung zu fahren. Alles weitere übernimmt der Computer.

Eine weitere Schwierigkeit besteht darin, daß die Bar-Codes äußerst exakt gedruckt werden müssen. Entsprechend teuer sind auch die Druckmaschinen für die Aufkleber.

Unsere Anwendung des Monats zeigt, daß sogar ein C 64 mit einem Epson FX80-Drucker und der richtigen Software in der Lage ist, diese Codes sauber zu Papier zu bringen.

Interessant ist auch, daß die gesamte Darstellung einer europäischen Norm entspricht. Wenn Sie also selbst ein Lesegerät besitzen, können Sie die Codes auswerten lassen.

(Dirk Henckels/tr)

Wichtig, um Eingabefehler in Warenwirtschaftssystemen zu vermeiden, sind maschinenlesbare Codes. Eine Schwierigkeit beim Drucken dieser Codes ist die hohe Anforderung an die Druckgenauigkeit. Ist diese geringer, müssen die Balken größer gedruckt werden. Daß auch ein Epson-Drucker solche Codes drucken kann, zeigt dieses Programm.

Wer sich beim Einkaufen Verpackungen schon einmal angesehen hat, wird meist auch ein Feld verschieden dicker dunkler Balken, den EAN-Code (EAN = Europäische Artikelnumerierung, Bild 1), gefunden haben, unter denen sich eine acht- oder dreizehnstellige Zahl befindet. Dieser Code kann von speziellen Computeranlagen gelesen werden (beispielsweise in Geschäften durch neuere Kassenanlagen); diese sind durch ein LAN (Local Area Network = lokales Netzwerk) mit Computern verbunden, die das Lager verwalten. Auf diese Weise kann jederzeit abgerufen werden, wieviel Stück eines bestimmten Produkts noch im Lager sind oder wieviel (zum Beispiel an einem Tag) verkauft worden sind. Ebenso kann der Computer automatisch nachbestellen, wenn für ein Produkt eine bestimmte Mindeststückzahl im Lager unterschritten wird. Kurz: Warenregistrierung durch maschinenlesbare Codes ist der Grundstock einer rationellen automatischen Lagerverwaltung. Dieses Programm liefert keine Lagerverwaltung (für ernstzunehmende Lösungen obigen Umfangs ist der C 64 einfach zu klein), sondern eine Voraussetzung dafür: die maschinenlesbaren Codes.

Zwei gedruckte Strichcodes mit den Ziffernfolgen 40 26600 13385 2 und 4026 6305
Bild 1. EAN-13 und EAN-8 von einem Epson-Drucker

Aufbau und Technik der EAN-Codes

Der EAN-Code besteht aus zwei Teilen: dem Balkenfeld und der Ziffernreihe. Der Computer kann nur die Balken »lesen«. Die Ziffern, ausschließlich »menschenlesbar«, bergen die gleichen Informationen: Länderkennung, bbn, Produktnummer und Prüfziffer (Bild 2).

Schreibmaschinentabelle mit Ziffernfolgen und Legende a bis d auf grauem Raster
Bild 2. Aufbau eines EAN-13-, EAN-8-Codes

Die Länderkennung ist international festgelegt; für Deutschland sind die Zahlen 40 bis 43 reserviert. Die bbn (Bundeseinheitliche Betriebsnummer) kann von jedem Unternehmen oder Privatmann gegen eine Gebühr beantragt werden. Sie ist fünfstellig und muß — soll auch EAN-8 (mit dreistelliger bbn) gedruckt werden — auf zwei Nullen enden. Diese Nullen werden für den EAN-Kurzcode dann weggelassen. Die Produktnummer kann von jedem Unternehmer willkürlich festgelegt werden. Dafür steht ihm der gesamte fünf-(EAN-13) beziehungsweise zweistellige (EAN-8) Zahlenbereich zur Verfügung. Für die Prüfziffer berechnet man die Summe der Produkte aus jeder der zwölf beziehungsweise sieben bereits festgelegten Ziffern und einem festgelegten Multiplikator. Die Prüfziffer ist die Differenz zwischen dem erhaltenen Wert und der nächsthöheren durch zehn teilbaren Zahl. Ist der Wert bereits durch zehn teilbar, ist die Prüfziffer null. Eine solche Rechnung zeigt Bild 3.

Drei Zeilen Schreibmaschinentext mit EAN-13, Multiplikator und Additionsrechnung mit Ergebnis
Bild 3. Berechnung der Prüfziffer

Die Balkenreihe ist folgendermaßen aufgebaut: ein Randzeichen, sechs Ziffernzeichen, ein Mittelzeichen, sechs Ziffernzeichen, ein Randzeichen. Die erste Ziffer der Zahlenreihe, Teil der Länderkennung, wird nicht codiert, sondern durch Kombination verschiedener Zeichensätze festgelegt. Jedes Zeichen setzt sich aus sogenannten Modulen zusammen. Jedes Modul kann, ähnlich einem Bit, zwei Zustände annehmen: dunkler (= gedruckter) beziehungsweise heller (= nicht gedruckter) senkrechter Balken. Alle Module sind gleich breit. Breitere Balken entstehen durch Aufeinanderfolgen von Modulen gleichen Zustands. Ziffernzeichen bestehen aus sieben, das Mittelzeichen aus fünf, die Randzeichen aus drei Modulen (Bild 4).

Punkt- und Rautenmuster für die Ziffern 0 bis 9 in drei Spalten A, B und C
Bild 4. Die nötigen Zeichensätze für EAN-Codes

Es stehen drei Zeichensätze (fortan mit »A« bis »C« bezeichnet) zur Verfügung. Zeichensatz C ist der gespiegelte Zeichensatz B und wird immer zwischen Mittelzeichen und rechtem Randzeichen verwendet. Die Kombination der Zeichensätze A und B in der ersten Hälfte (bis zum Mittelzeichen) ergibt die erste Zahl der Länderkennung, die ja nicht durch Module dargestellt wird. Das hat folgenden Sinn: Bereits vor Entstehung des EAN-Codes existierte in den USA ein ähnlicher Code, der 12stellige UPC-Code. Der Aufbau ist derselbe, jedoch ist die Länderkennung nur 1stellig (daher auch nur 12, nicht 13 Zeichen), und es wird nur mit den Zeichensätzen A und C gearbeitet, da ja keine dreizehnte Ziffer codiert werden muß. Die EAN-13-Lesegeräte können auch UPC decodieren: Wird in der ersten Hälfte nur Zeichensatz A verwendet, ist die ausgegebene Länderkennung »0x« (= USA) — unabhängig davon, ob unter dem Balken zwölf oder dreizehn Ziffern stehen.

Zum Programm

Das Programm (siehe Listing) entstand eigentlich aus einer Verlegenheit heraus. Versandkartons für ein Industrieunternehmen waren versehentlich nicht mit EAN-Codes bedruckt worden. Da jedoch für eine Reklamation keine Zeit mehr vorhanden war, mußten die zum Versand nötigen Barcodes auf andere Weise erstellt werden. Dazu diente Version I des Programms. Das Listing zeigt die (unter anderem um absturzsichere Eingaberoutinen) erweiterte und besser strukturierte Version II.

In Zeile 16 wird in N$ die bbn festgelegt. Da in der Regel hauptsächlich eine bbn verwendet wird, ist diese Voreinstellung sinnvoll. Trotzdem ist die bbn voll editierbar, um sich nicht auf eine bbn festlegen zu müssen. Die Prüfziffer wird nicht mit eingegeben, sondern in Zeile 23 bis 31 berechnet und ausgegeben. Die Zeichensatzabfolge wird anhand der ersten Ziffer der Länderkennung in Zeile 33 und 34 abgelegt. Die Zeilen 36 bis 42 legen die Modulabfolge fest, die dann in den Zeilen 44 bis 49 in druckerverständliche Codes übersetzt wird. In Zeile 51 wird der Drucker angesprochen. Die Sekundäradresse wurde so gewählt, daß keine Umcodierung durch das Interface erfolgt, um — eventuell bei entsprechender Änderung der Sekundäradresse — das Umsetzen auf andere Interfacetypen zu erleichtern (zum Beispiel Data-Becker-Interface: Sekundäradresse 7). In jedem Fall wird jedoch ein Epson- oder Epson-Steuercode-kompatibler Drucker vorausgesetzt.

Bis Zeile 58 erfolgt der Ausdruck der Balken, bis Zeile 64 der der Klarschrift. Die Zeilen 78 bis 87 beinhalten die drei Zeichensätze für die Ziffern Null (Zeile 78) bis neun (Zeile 87). Zeile 88 und 89 enthalten die Kombination der Zeichensätze A und B für die Länderkennungen »0x« bis »9x«. F$ und L$ (Zeile 93 und 94) enthalten die Druckerübersetzung für ein dunkles beziehungsweise helles Modul. Durch Variation der Länge dieser Strings sowie des Wertes der Variable RC in Zeile 52 kann die Größe des Balkenfeldes geändert werden. Allerdings kann, je nach Drucker und -verfahren, die Lesesicherheit der Codes beeinträchtigt werden, wenn die Größe zu klein gewählt wird. Ebenso muß bei einer derartigen Änderung der Klartextausdruck entweder angepaßt oder weggelassen werden. Letzteres ist möglich, da die Lesegeräte ausschließlich das Balkenfeld, nicht aber die Klarschrift entziffern können. Daher ist es auch unwesentlich, daß das Programm den Epson-internen Zeichensatz und nicht den empfohlenen OCR-B-Zeichensatz verwendet.

In Zeile 53 bis 64 kommt ein Steuercode vor, der ESC beziehungsweise chr$(27) entspricht. Er erscheint auf dem Bildschirm als inverse eckige Klammer auf und wird angegeben als <Control>-<:>.

Drucktechnik und Druckeranpassung

Der für die Balken gewählte Grafikmodus hat eine Auflösung von 1920 Punkten pro Zeile. Diese Auflösung gewährt die größte Flexibilität hinsichtlich der Codegröße. Andere Auflösungen führen bei entsprechender Änderung von F$ und L$ zu ähnlichen Ergebnissen. Außerdem wurde der für Textdruck eingebaute Doppeldruckmodus für den Grafikausdruck simuliert. In diesem Modus wird jede Zeile zweimal gedruckt, und zwar mit einem vertikalen Versatz von 1/3 Punktdurchmesser (1/216 Zoll). Dadurch wirkt eine senkrechte Linie nicht mehr in Punkte aufgelöst, sondern durchgehend. In Zusammenhang mit der hohen horizontalen Auflösung entsteht auch bei nicht mehr so neuem Farbband noch eine durchgehende Fläche, keine Ansammlung von Punkten als Balken.

Verwendete Codes zur Druckeransteuerung:

ESC @Klammeraffe: Drucker-Reset
ESC chr$(108) chr$(10): setzt linken Rand auf 10
ESC 3 chr$(1): setzt Zeilenvorschub auf 1/216 Zoll
ESC 1: setzt Zeilenvorschub auf 7/72 Zoll
ESC 2: setzt Zeilenvorschub auf 1/6 Zoll
ESC a: 96 Zeichen/Zeile
ESC g: Doppeldruck (s.o.)
ESC W 1 bzw. 0: Breitschrift ein bzw. aus
ESC * chr$(3) chr$(58) chr$(2): Die nächsten 570 Bytes werden im 1920-Pixel-Grafik-Modus gedruckt.

Eine Anpassung an andere, nicht Epson-kompatible Drucker müßte ohne größere Schwierigkeiten möglich sein.

(Dirk Henckels/tr)
1 rem ------------------------------
2 rem ------- ean 13 / ean 8 -------
3 rem ------------------------------
4 rem ------- dirk henckels --------
5 rem ---- julius-leber-str. 26 ----
6 rem ------ 4018  langenfeld ------
7 rem ------ tel. 02173/73369 ------
8 rem ------------------------------
9 :
10 poke53280,0:poke53281,0:poke788,52:poke792,226:poke793,252:gosub65
11 print"{clr}{lblu}","{left}{CBM-@}{CBM-@}{CBM-@}{CBM-@}{CBM-@}{CBM-@}{CBM-@}{CBM-@}{CBM-@}{CBM-@}{CBM-@}{CBM-@}{CBM-@}{CBM-@}{CBM-@}{CBM-@}{CBM-@}{CBM-@}{CBM-@}{CBM-@}{CBM-@}{CBM-@}"
12 print,"{left}{rvon} ean-barcodes  8 / 13 "
13 printtab(4)"{yel}{down}ean-stellenzahl (13 bzw. 8) : {wht}{down}{CBM-T}{CBM-T}{up}{left}{left}";
14 gosub100
15 print"{down}{lred}   anzahl zu druckende etiketten: {wht}{down}{CBM-T}{CBM-T}{CBM-T}{up}{left}{left}{left}";
16 gosub110:n$="4026600":c=7:l=5
17 ifean=8thenn$=left$(n$,5):c=5:l=2
18 printtab(14-ean/2)"{down}{lgrn}ean-code:  {wht}"n$spc(l+1)"{lgrn}p{wht}"
19 ifean=13thenprinttab(18)"{CBM-T}{CBM-T}{CBM-T}{CBM-T}{CBM-T}{CBM-T}{CBM-T}{CBM-T}{CBM-T}{CBM-T}{CBM-T}{CBM-T}{up}{left}{left}{left}{left}{left}";
20 ifean=8thenprint,,"{rght}{CBM-T}{CBM-T}{CBM-T}{CBM-T}{CBM-T}{CBM-T}{CBM-T}{up}{left}{left}";
21 gosub119
22 :
23 c1=3
24 forc=ean-1to1step-1
25 :s=s+(val(mid$(n$,c,1))*c1)
26 :ifc1=1thenc1=3:goto28
27 :c1=1
28 next
29 p$=right$(str$((int(s/10)+1)*10-s),1)
30 print" {lgrn}";p$
31 n$=n$+p$
32 :
33 ifean=13thenzs$=zs$(val(left$(n$,1)))+"cccccc"
34 ifean=8thenzs$="aaaacccc"
35 :
36 b$="101"
37 ifean=13thenforc=2to13:c1=c-1
38 ifean=8thenforc=1to8:c1=c
39 :b$=b$+z$(val(mid$(n$,c,1)),asc(mid$(zs$,c1,1))-65)
40 :if(c=7andean=13)or(c=4andean=8)thenb$=b$+"01010"
41 next
42 b$=b$+"101"
43 :
44 c=0
45 forc1=1to95
46 :iflen(d$(c))=>250thenc=c+1
47 :ifmid$(b$,c1,1)="1"thend$(c)=d$(c)+f$:goto49
48 :d$(c)=d$(c)+l$
49 next
50 :
51 open1,4,4:rem g\rlitz-interface ohne umcodierung
52 rc=17:ifean=8thenrc=12
53 forc=1toe:print#1,"{esc}@{esc}"chr$(108)chr$(15);
54 forc0=1torc:forc1=1to2
55 print#1,d$(0)d$(1)d$(2);
56 ifc1=1thenprint#1,"{esc}3{CTRL-A}"chr$(13)chr$(10);:goto58
57 ifc0<rcthenprint#1,"{esc}1"chr$(13)chr$(10);
58 next:next
59 :
60 print#1,"{esc}2"chr$(13)chr$(10)"{esc}m{esc}g";
61 ifean=8thenprint#1," {esc}w1"left$(n$,4)" {esc}w0 {esc}w1"right$(n$,4);:goto64
62 print#1,"{esc}w1"left$(n$,2)"{esc}w0 {esc}w1"mid$(n$,3,5)"{esc}w0 {esc}w1";
63 print#1,mid$(n$,8,5)"{esc}w0 {esc}w1"right$(n$,1);
64 print#1,chr$(13)chr$(10)chr$(10);:next:print#1,"{esc}@":close1:run
65 :
66 :
67 : rem unterprogramme
68 :
69 : rem vorbereitung & titel
70 :
71 printchr$(142)"{clr}{dish}{wht} {rvon}  {CBM-I}{CBM-I}{CBM-I}{CBM-I}{CBM-I}{CBM-I}{CBM-I}{CBM-I}{CBM-I}{CBM-I}{CBM-I}{rvof}{CBM-V}{CBM-I}{rvon}    {rvof}{CBM-I}      {rvon}{CBM-K} {rvof}{CBM-K}  {rvon}{CBM-I}  {CBM-I}  {CBM-I}{rvof}"
72 print" {rvon}  {rvof}          {CBM-I}{rvon} {CBM-D}{rvof}{CBM-V}{rvon}  {rvof}{CBM-C}{rvon}{CBM-F} {rvof}{CBM-I}    {rvon}{CBM-K} {rvof}{CBM-K}  v{rvon}er{rvof}s{rvon}io{rvof}n"
73 print" {rvon}  {rvof}        {CBM-I}{rvon} {CBM-D}{rvof}{CBM-V}  {rvon}  {rvof}  {CBM-C}{rvon}{CBM-F} {rvof}{CBM-I}  {rvon}{CBM-K} {rvof}{CBM-K}   {rvon}  {rvof} {rvon}  {rvof}"
74 print" {rvon}  {CBM-I}{CBM-I}{CBM-I}{CBM-I}{CBM-I}{rvof}{CBM-V}{CBM-I}{rvon} {CBM-D}{rvof}{CBM-V} {rvon}{CBM-I}{CBM-I}{CBM-I}  {rvof}    {CBM-C}{rvon}{CBM-F} {rvof}{CBM-I}{rvon}{CBM-K} {rvof}{CBM-K}   {rvon}  {rvof} {rvon}  {rvof}"
75 print" {rvon}  {rvof}{CBM-I}{CBM-I}{CBM-I}{CBM-I}{CBM-I}{rvon} {CBM-D}{rvof}{CBM-V}      {rvon}  {rvof}      {CBM-C}{rvon}{CBM-F}  {rvof}{CBM-K}  {CBM-I}{rvon}  {rvof}{CBM-I}{rvon}  {rvof}{CBM-I}"
76 print"{down}{down}{down}{rght}{rght}{rght}{rght}{rght}{rght}{rght}{lblu}written 1986 by d.henckels"
77 print,"{down}all rights reserved."
78 data"0001101","0100111","1110010"
79 data"0011001","0110011","1100110"
80 data"0010011","0011011","1101100"
81 data"0111101","0100001","1000010"
82 data"0100011","0011101","1011100"
83 data"0110001","0111001","1001110"
84 data"0101111","0000101","1010000"
85 data"0111011","0010001","1000100"
86 data"0110111","0001001","1001000"
87 data"0001011","0010111","1110100"
88 data"aaaaaa","aababb","aabbab","aabbba","abaabb"
89 data"abbaab","abbbaa","ababab","ababba","abbaba"
90 dimz$(9,2),zs$(9),d$(2)
91 forc=0to9:forc1=0to2:readz$(c,c1):next:next
92 forc=0to9:readzs$(c):next
93 f$=chr$(255)+chr$(255):f$=f$+f$+f$
94 l$=chr$(0)+chr$(0):l$=l$+l$+l$
95 d$(0)=chr$(27)+"*"+chr$(3)+chr$(58)+chr$(2):d$(1)="":d$(2)=""
96 forc=1to5000:next:poke198,0:wait198,1:return
97 :
98 : rem eingabe ean-groesse
99 :
100 print"R {left}{left}";
101 getn$:ifn$<>"1"andn$<>"8"goto101
102 ifn$="1"thenn$="13"
103 ean=val(n$):printn$;:poke211,34
104 getn$:ifn$<>chr$(13)andn$<>chr$(20)then104
105 ifn$=chr$(20)thenpoke211,34:goto100
106 print:return
107 :
108 : rem eingabe anzahl codes
109 :
110 c=0:n$=""
111 getx$:ifc<3thenprint"R{left}";
112 ifx$=chr$(13)andcthenprint" ":e=val(n$):return
113 ifx$=chr$(20)andcthenc=c-1:n$=left$(n$,c):printx$;:goto111
114 ifx$=>"0"andx$<="9"andc<3thenc=c+1:n$=n$+x$:printx$;
115 goto111
116 :
117 : rem eingabe klartext
118 :
119 getx$:ifc<ean-1thenprint"R{left}";
120 ifx$=chr$(13)andc=ean-1thenreturn
121 ifx$=chr$(20)andcthenc=c-1:n$=left$(n$,c):print"{left}R {left}{left}";:goto119
122 ifx$=>"0"andx$<="9"andc<ean-1thenc=c+1:n$=n$+x$:printx$;
123 goto119
Listing »EAN-Barcodes« für C 64 und Epson-Drucker
PDF Diesen Artikel als PDF herunterladen
Mastodon Diesen Artikel auf Mastodon teilen
← Vorheriger ArtikelNächster Artikel →