optimizacion de la rutina

Anuncio
LABORATORIO
E
S C U E L A
T
É C N I C A
S
U P E R I O R
D E
DE
I
MICROPROCESADORES
N G E N I E R O S
I
N D U S T R I A L E S
Y
D E
T
E L E C O M U N I C A C I Ó N
UNIVERSIDAD DE CANTABRIA
HARDWARE Y SOFTWARE
DE UN
LECTOR DE
CÓDIGOS DE BARRAS
PRÁCTICA 3
JAIME GÓMEZ OBREGÓN
PAULINO CANTERO GUTIÉRREZ
ESTUDIOS DE INGENIERÍA TÉCNICA DE TELECOMUNICACIÓN
ESPECIALIDAD EN SISTEMAS ELECTRÓNICOS
Se ha construido un lector de códigos de barras y el software correspondiente para
hacerlo funcionar en un Motorola 68000. El objetivo inicial de la práctica es leer
números binarios representados en forma de códigos de barras.
Hemos llevado al extremo tanto el diseño del sensor, que permite distinguir barras de un
ancho mínimo de 400 micras, como la programación del software, consiguiendo la
decodificación completa del estandar europeo EAN-13, el más difundido en España para
aplicaciones comerciales.
Práctica
3
Introducción
Dada la envergadura de este trabajo y el tiempo empleado en llevarlo a cabo, creemos
que no es oportuno convertir esta memoria en un comentario pormenorizado del trabajo
realizado, ni en una descripción detallada del software que se adjunta. Si recogeremos,
sin embargo, los principales problemas surgidos durante la práctica y las características
más relevantes del diseño, justificando adecuadamente las decisiones más importantes
que se han tomado en cada caso.
Estimamos que las partes más importantes del diseño sea la cabeza lectora y el hardware
de generación de interrupción, que veremos ahora con más detalle.
Cabeza lectora
Como una primera aproximación al diseño pensamos en construir el
sensor con la forma de un lápiz que se pasaría sobre el código de barras.
Analizando la intensidad de la luz ambiente reflejada que incidiría sobre
el fototransistor se podría generar una interrupción al microprocesador
por cada transición blanco/negro.
La ambición de llevar la práctica más allá de lo meramente
experimental, dotando al diseño de utilidad real y de la capacidad de leer códigos reales,
y -por qué no- el reto de construir un prototipo útil con componentes de bajo coste, nos
llevó a desestimar finalmente esta idea. Un sensor tipo lápiz es demasiado dependiente
de la iluminación ambiente, y sensible a brillos o imperfecciones en la tinta impresa.
Por último, para recoger la luz reflejada con un diseño de estas características sería
necesario aumentar demasiado la superficie fotosensible, y los códigos habrían de
escalarse mucho para ser legibles, imposibilitando la lectura de códigos pequeños.
Para solucionar estos problemas insertamos el fotransistor en un taco de madera
perforado, limitando la entrada de luz con dos bandas paralelas de cinta aislante negra
separadas aproximadamente medio milímetro. El sensor se desliza apoyado sobre el
código de barras, insensibilizandose así frente a brillos y perturbaciones externas. La
resolución aumenta notablemente de este modo.
Se decidió también insertar una fuente
de luz en el taco de madera, con una
inclinación de 90º respecto al
fototransisor, y ambos a 45º del papel.
Se cubren así dos objetivos:
proporcionar una fuente de luz
controlable que incide directamente
sobre el papel, sustituyendo a la luz
ambiental e independizándola de ésta, y
maximizar la sensibilidad del
fototransistor.
Detalle de la cabeza lectora. La separación entre las
bandas determina la resolución del lector y la intensidad
de la luz que incide en el fototransistor.
En efecto, estudiando las gráficas de sensibilidad del
fototransistor BPW77N se observa que para una
longitud de onda de 400 ó 600 nm (luz visible), la
sensibilidad máxima es del 40% (véase figura adjunta
). Utilizando el diodo infrarrojo (800 nm) de un
mando a distancia estropeado de un televisor
logramos incrementar la sensibilidad hasta el 92%
aproximadamente. Esto es determinante para la calidad final del lector, pues el
fototransistor es la piedra angular del diseño y es prioritario maximizar tanto la
intensidad de la luz que recibe como su “calidad” (longitud de onda).
Esquema hardware
Antes de montar el circuito lo simulamos para comprobar que nuestro esquema inicial
se ajusta al funcionamiento deseado. Son necesarios los siguientes componentes.
•
•
•
•
•
•
•
•
•
•
74LS175. 4 flip-flops tipo D.
2 x 74LS75. Cada uno con 4 latches.
SN7405. Seis inversores en colector abierto.
74LS02. Cuatro puertas NOR.
LM311. Comparador.
74LS86. Cuatro puertas XOR.
9 Resistencias, mayoritariamente para cargar los colectores de los negadores o-c
y de polarización.
Un potenciometro variable, para la calibración del comparador.
Un diodo infrarrojo genérico.
Fototransistor BPW77N
Y el esquema eléctrico es el que se muestra en la figura de la página siguiente. Consta
de un bloque analógico formado por la cabeza lectora y un comparador ajustable
mediante un potenciómetro que fija un umbral de comparación. De esta forma se
simplifica la calibración del lector para diferentes tintas o contrastes de colores.
Para minimizar la lógica de direccionamiento se asume que dos únicos bits de memoria
se repiten en todo el espacio de memoria destinado a hardware del microprocesador.
Así, las direcciones pares activan el latch de lectura de dato, y las impares provocan la
activación del latch de reset de interrupción. Un tercer latch impide interrupciones
concurrentes o el apagado eventual de una interrupción no atendida (bloqueo de
interrupción)
Por último, el circuito de generación de DTACK consiste en una retardo a través de dos
flip-flops activados por un reloj de 8 MHz.
El funcionamiento es como sigue. La tensión a la entrada del comparador es un valor
analógico proporcionado por el fototransistor. La comparación se hace con una tensión
umbral establecida previamente variando un potenciómetro y que es función de la
calidad del papel y de la tinta
empleada en el código de barras.
Esta tensión se establece como la
media aritmética de la tensión con
el sensor sobre un área blanca y la
tensión sobre un área negra (tinta).
El comparador actúa, por lo tanto,
como convertidor A/D.
Reverso del montaje, donde puede verse cómo se han
enfrentado el fototransitor y el fotodiodo dentro de la cabeza
lectora.
El bit generado puede leerse en
cualquier momento activando el
latch direccionado con las líneas
impares del mapa de memoria.
Si se produce una transición entre colores (la cabeza lectora se desliza entre dos barras),
se genera una interrupción que queda convenientemente bloqueada por un tercer latch,
de modo que solo la acción del software, activando el latch conectado a las líneas pares
del espacio de direccionamiento, provoca el reset de dicha interrupción.
Determinar la longitud de cada barra es fundamental para decodificar correctamente el
código. Se ha utilizado la PI/T del sistema para establecer una aproximación entre el
ancho de cada barra y el tiempo que el usuario emplea en atravesarla con el sensor. Esto
es muy problemático, pues la velocidad de pasada no será nunca constante y esto
desvirtúa los tiempos medidos y en consecuencia el código numérico a decodificar.
Afortunadamente se ha encontrado una elaborada solución software a este
inconveniente, que se comentará más adelante.
Resultan ilustrativas las siguientes gráficas. La primera representa las variación de
tensión en el fototransistor a medida que el sensor avanza sobre un código de barras
EAN-13.
La segunda gráfica es la representación binaria del mismo código, una vez digitalizado
y filtrado. Como se explicará más adelante, antes de la decodificación se filtran los
glitches producidos por el ruido en el circuito o pequeñas imperfecciones en el papel.
Estas perturbaciones provocan “interrupciones extra” en intervalos mucho más breves
que los que provocaría una barra válida, y son descartadas por software.
Estándares de codificación
Sería inviable tratar aquí todos los estándares de codificación que se aplican en la
industria y el comercio de todo el mundo. Los códigos de barras, por su bajo coste de
implementación y las ventajas que aportan al control de inventarios, automatización de
procesos, identificación de productos, etcétera, son cada vez más comunes y sus
aplicaciones más variadas.
A modo de ejemplo se reproduce a continuación una etiqueta “ODETTE” para
identificación industrial, y algunos ejemplos de estándares comerciales para códigos de
barras unidimensionales y bidimensionales.
Como puede intuirse, cada estandar está especializado en un ámbito determinado,
ofreciendo todos ellos distintas prestaciones en cuanto a densidad, redundancia
(comprobación de errores) o alfabeto codificable.
Nuestro diseño se centra en el estandar europeo EAN-13, muy utilizado en España para
aplicaciones comerciales y control de inventario.
El estándar EAN-13 codifica 12 dígitos del 0 al 9, y un dígito de control de error
(checksum). Consta de treinta barras negras y treinta blancas, cada una de ellas con
cuatro anchuras posibles. Existen dos símbolos indicadores de inicio y fin de secuencia
(véase la figura en la página anterior), codificados como “101”, y un símbolo que separa
el código en dos partes iguales (“01010”).
Las especificaciones completas pueden verse en internet (http://www.ean-int.org) y son
más complejas. Nuestra implementación en ensamblador puede leerse comentada en el
código fuente que acompaña a esta memoria.
Básicamente podría decirse que cuatro barras codifican un dígito. En la parte derecha
del código la relación es unívoca: a cada representación gráfica corresponde un dígito
decimal. En la parte izquierda la decoficación es más complicada, pues existen dos
alfabetos mezclados libremente, de modo que a un dígito le corresponden dos posibles
representaciones gráficas. El orden en que se han mezclado los alfabetos determina un
carácter adicional, que se coloca antes que todos los demás.
La decodificación es un proceso complejo, se recomienda leer el código comentado en
ensamblador para conocer con más detalle el proceso.
Software
Debido a la magnitud de la práctica el programa de control del lector de códigos de
barras es bastante extenso, por lo que trataremos directamente los puntos que creemos
más interesantes del desarrollo software, sin detallar los aspectos menos significativos.
Captura de pantalla de la salida del programa, con información de debugging. Obsérvense los tiempos, en
ciclos, proporcionados por la PI/T (columnas de la izquierda), y los resultados parciales obtenidos en el
proceso de decodificación, que concluyen con la representación binaria del dígito leído (última columna).
Uno de los principales problemas es el control de las interrupciones generadas por el
hardware y la atención de las mismas. La solución a este inconveniente es múltiple. Por
una parte se hizo preciso identificar y posteriormente desestimar interrupciones
provocadas por brillos o ruido eléctrico. Se creó un umbral de tiempos, por debajo del
cual las interrupciones son tan rápidas que no son consideradas válidas. Los resultados
fueron muy positivos.
Por otra parte, para ofrecer cierta redundancia frente a fallos, brillos, glitches e
imperfecciones en el papel y la distribución de la tinta, se comprueba el latch que
guarda el bit de color blanco/negro, y se compara con el bit de la transición anterior, de
modo que dos una transición válida ha de suponer necesariamente un cambio en este
latch.
Después de conseguir gestionar de una manera óptima el control de las interrupciones y
con ello las transiciones blanco/negro era necesario realizar uno de los bloques más
importantes del programa, la encargada de sacar el código en el formato estandar, el
cual tiene cuatro tipos de grosores de barras por lo que es realmente difícil de
decodificar con el hardware que podíamos utilizar, y lo que es aun más difícil de
controlar que es la velocidad con que se pasa el lector, la cual debería ser constante,
aunque en realidad es realmente imposible conseguirlo de forma manual. Por tanto para
poder restringir al mínimo el error producido por estos motivos conseguimos diseñar un
algoritmo que consiste en hacer una “lectura a tramos”, es decir si cada número del
código tiene cuatro transiciones, sacamos el patrón unidad de estas cuatro barras
sumando el tiempo total de estas y dividiendo entre cuatro, pasando después a comparar
cada barra con este patrón para saber su anchura, con lo cual la velocidad de pasada en
cada número no influye en los demás consiguiendo así depender lo menos posible de la
velocidad de pasada.
Teniendo en cuenta el algoritmo anterior conseguimos sacar el tiempo de transición de
cada barra con el cual identificamos el número binario conseguido en la lectura con una
tabla estandar mediante comparaciones hechas en una pequeña rutina que nos da
finalmente el código completo.
********************INSETA LA TABLA DE LOS CODIGOS SI LA TIENES
POR AHÍ*****************************************
Una vez tenemos el código completo solo quedaría sacarlo por pantalla, aunque antes
de eso y después de muchas pruebas se producen numerosos errores de los cuales
algunos hemos conseguido detectar principalmente de dos forma. La primera es
mirando si cada número del código consta de 7 bits, ya que todos están formados por el
mismo numero de bits y si es así identificándolo con uno de la tabla, en el caso de que
se detecte un error el programa sacaría por pantalla un carácter indicando el lugar del
fallo en el código y dando la posibilidad de volver a pasar el lector.
Otra forma de detectar errores es más propio del tipo de código, ya que el último
número de cada código es resultado de un algoritmo de operaciones, las cuales realiza el
programa y compara el resultado con el número leído en el papel, si fuese una lectura
correcta también se indicaría en la salida por pantalla.
* LABORATORIO DE MICROPROCESADORES - PRACTICA TRES
* ---------------------------------------------------------------------------* Jaime Gomez Obreg¢n y Paulino Cantero Guti‚rrez.
*
WRITE
OUTCHR
WRITELN
RETURN
INSTAT
EQU
EQU
EQU
EQU
EQU
$0023
$0020
$0024
$0063
$0001
; Llamadas a la TRAP #15.
; VERSION LABORATORIO
INT
CODIGO
PILA
DATOS
EQU
EQU
EQU
EQU
$9000
$4000
$5000
$7000
; Offsets del programa.
XREF
STRING
INT2STR
MACRO
MOVE.B
MOVE.B
PEA
BSR
ADD.L
ENDM
QUE
#10,-(A7)
#'B',-(A7)
QUE
STRING
#10,A7
; Converte un Entero a un String.
PRINT
MACRO
MOVE.L
SYSCALL
ENDM
QUE
#QUE,-(A7)
WRITE
; Macro que escribe un String.
; VERSION LABORATORIO.
PINTA
MACRO
MOVE.B
SYSCALL
ENDM
CARACTER
CARACTER,-(A7)
OUTCHR
; Macro que escribe un caracter.
; VERSION LABORATORIO
SYSCALL
MACRO
TRAP
DC.W
ENDM
FUNCION
#15
FUNCION
; VERSION LABORATORIO
******************************************************************************
ORG
INT
******************************************************************************
* Esta rutina utiliza la PIT para determinar el tiempo transcurrido entre las
* transiciones, que ser� proporcional al ANCHO DE LA BARRA le�da.
* Almacena estos datos sucesivamente en MATRIX.
******************************************************************************
*
*
*
*
*
*
*
*
*
*
*
*
SIGUE
*
SALTAR
*
MOVEM.L
MOVE.L
MOVE.W
D0/D1/A0,-(A7)
#$EF0000,A0
(A0),D0
CMP.W
BEQ
PINTA
GLOBAL,D0
SALTAR
D0
MOVE.W
D0,GLOBAL
MOVE.L
MOVE.W
INT2STR
MOVE.L
SYSCALL
PINTA
CUENTA,D0
D0,-(A7)
S_MILISGS
#S_MILISGS,-(A7)
WRITE
#':'
BCLR.B
MOVE.L
MOVEP.L
MOVE.L
SUB.L
#0,TCR
#CR,A0
(A0),D0
#250000,D1
D0,D1
; Paramos el reloj.
; Escribimos el tiempo transcurrido.
MOVE.B
MOVE.L
MOVE.L
MOVEP.L
#%10100000,TCR
#250000,D0
#CPR,A0
D0,(A0)
; Configuraci�n del TCR con preescalador.
; 1/8MHz*(32_del_preesc.)*250000=1 s.
BSET
#0,TCR
; Reloj en marcha.
MOVE.L
ASL.L
ADD.L
MOVE.L
MOVE.L
CUENTA,D0
#2,D0
#MATRIX,D0
D0,A0
D1,(A0)
MOVE.W
INT2STR
MOVE.L
SYSCALL
CMP.W
BHI
BRA
ADD.L
PINTA
PINTA
MOVEM.L
RTE
D1,-(A7)
S_MILISGS
#S_MILISGS,-(A7)
WRITE
#300,D1
SIGUE
SALTAR
#1,CUENTA
#'/'
#'p'
(A7)+,D0/D1/A0
; Hacemos el RESET de la interrupt.
; OPTIMIZABLE.
; Escribe el n�mero de barra.
; Porque la PIT cuenta hacia abajo.
; x4.
; Almacenamos en la matriz el ancho
; de la columna reci�n le�da.
; Y lo escribimos en pantalla.
; Incrementamos �ndice de la matriz.
******************************************************************************
DIVIDE
******************************************************************************
* Hace una divisi�n e imprime en pantalla el cociente con dos decimales.
* Recibe en D0 la anchura de la barra,
*
en D2.W el patr�n unidad
* Devulve en D3 el resultado multiplicado por 100.
******************************************************************************
MOVEM.L
DIVU
MOVE.L
MULU
MOVE.W
INT2STR
PRINT
D0/D6,-(A7)
D2,D0
D0,D6
#100,D6
D0,-(A7)
CADENA
CADENA
SWAP
CMP.W
BEQ
PINTA
D0
#$0,D0
EXACTA
#44
MULU
DIVU
MOVE.W
INT2STR
PRINT
#10,D0
D2,D0
D0,-(A7)
CADENA
CADENA
MOVE.W
MULU
SWAP
D0,D3
#10,D3
D0
MULU
DIVU
MOVE.W
INT2STR
PRINT
#10,D0
D2,D0
D0,-(A7)
CADENA
CADENA
ADD.W
BRA
D0,D3
TERMI
CLR.L
PINTA
PINTA
PINTA
D3
#$20
#$20
#$20
PINTA
ADD.L
MOVEM.L
RTS
#'�'
D6,D3
(A7)+,D0/D6
; En D6.W el cociente x100.
; Y escribimos el resultado
; Si el resto es 0 no se escriben decimales.
; la coma; (no compila si ponemos el char.)
; Multiplicamos el resto por 10.
; y hallamos un decimal.
; Primer decimal.
; Segundo decimal.
EXACTA
TERMI
; Importante para las divs. exactas.
; En D3 devolvemos el resultado x100.
******************************************************************************
MATRIX_OUT
******************************************************************************
* Extrae un dato de MATRIX, con eco en pantalla.
* Recibe en D1 un puntero a un elemento de la matriz.
* Devuelve en D0 el elemento pedido.
******************************************************************************
MOVEM.L
A0-A1/D1,-(A7)
CLR.L
D0
MOVE.L
D1,A0
MOVE.W
(A0),D0
MOVE.W
D0,-(A7)
INT2STR
S_MILISGS
PRINT
S_MILISGS
TERM
CMP.W
BHI
PINTA
CMP.W
BHI
PINTA
CMP.W
BHI
PINTA
CMP.W
BHI
PINTA
#9999,D0
TERM
#$20
#999,D0
TERM
#$20
#99,D0
TERM
#$20
#9,D0
TERM
#$20
MOVEM.L
RTS
(A7)+,A0-A1/D1
******************************************************************************
PROCESA_SEIS
******************************************************************************
* Procesa los seis elementos de la matriz a los que apunta D1, mostrando por
* pantalla los resultados.
* Recibe en D1 el puntero al primero de los seis elementos.
******************************************************************************
MOVE.W
#0,D5
; D5 es el �ndice del bucle.
INIBUCLE CLR.L
D2
; Vamos a sumar todos los antxos en D2.
CLR.L
D4
PRINT
LINEA51
VECES_4
BSR
PINTA
ADD.L
ADD.L
ADD.B
CMP.L
BNE
MATRIX_OUT
#'�'
#4,D1
D0,D2
#1,D4
#4,D4
VECES_4
PINTA
PINTA
PINTA
PINTA
PINTA
PINTA
#$20
#$20
#$20
#$20
#$20
#'�'
DIVU
MOVE.W
INT2STR
PRINT
#$7,D2
D2,-(A7)
S_MILISGS
S_MILISGS
CMP.W
BHI
PINTA
CMP.L
BHI
PINTA
#9999,D2
TERM2
#$20
#999,D2
TERM2
#$20
PINTA
#'�'
SUB.W
MOVE.B
#$10,D1
#00,D4
MOVE.L
CLR.L
MOVE.W
BSR
BSR
ADD.L
D1,A0
D0
(A0),D0
DIVIDE
UMBRALES
#4,D1
ADD.B
CMP.L
BNE
#1,D4
#4,D4
VECES4
PRINT
PINTA
PINTA
LINEA52
#$0D
#$0A
ADD.W
CMP.W
BNE
RTS
#1,D5
#6,D5
INIBUCLE
TERM2
VECES4
;
;
;
;
;
Espacio.
Espacio.
Espacio.
Espacio.
Espacio.
; Ahora D2.W tiene el numero
; m�gico para comparar.
; Nuevamente apuntamos a la primera
; BARRA SIGNIFICATIVA del digito.
; D4 es el �ndice del bucle interior.
; En D0 la anchura de la barra.
; Dividimos
; y comparamos.
******************************************************************************
UMBRALES
******************************************************************************
* Recibe en D3 el ancho relativo de la barra (cociente), identificando en con* secuencia el ancho en bits de la barra, que escribe en RISTRA.
* Destruye A0 y D0.
******************************************************************************
MOVE.L
ADD.W
ADD.B
#RISTRA,A0
CUENTA,A0
#1,PARES
*
*
BTST
BEQ
BRA
#0,PARES
MULTI
SIG
MULTI
CMP.W
BGT
MOVE.B
BRA
CMP.W
BGT
MOVE.B
BRA
CMP.W
BGT
MOVE.B
BRA
MOVE.B
BRA
#145,D3
MAYOR11
#1,(A0)
VOLVER
#254,D3
MAYOR21
#2,(A0)
VOLVER
#366,D3
MAYOR31
#3,(A0)
VOLVER
#4,(A0)
VOLVER
; � > 1,26 ?
SIG
CMP.W
BGT
MOVE.B
BRA
#151,D3
MAYOR1
#1,(A0)
VOLVER
; � > 1,51 ?
MAYOR1
CMP.W
BGT
MOVE.B
BRA
CMP.W
BGT
MOVE.B
BRA
MOVE.B
#262,D3
MAYOR2
#2,(A0)
VOLVER
#375,D3
MAYOR3
#3,(A0)
VOLVER
#4,(A0)
; � > 2,69 ?
MOVE.B
ADD.W
RTS
(A0),D0
#1,CUENTA
MAYOR11
MAYOR21
MAYOR31
MAYOR2
MAYOR3
VOLVER
; � > 2,24 ?
; � > 3,16 ?
; � > 3,79 ?
******************************************************************************
DECOD_IZQ
******************************************************************************
* Convierte un conjunto de siete bits a un digito, de acuerdo al alfabeto de* finido para la PARTE IZQUIERDA del c�digo de barras (formato EAN-13).
* Recibe en A0 un puntero al primer elemento de la matriz del area izquierda.
******************************************************************************
AGAIN
OTRA2
*
*
OTRA3
MAL
CLR.L
MOVE.L
CLR.L
CLR.L
CLR.L
CLR.L
D6
#RISTRA,A0
D0
D1
D2
D3
MOVE.B
MULU
MOVE.B
MULU
MOVE.B
MULU
MOVE.B
(A0)+,D0
#1000,D0
(A0)+,D1
#100,D1
(A0)+,D2
#10,D2
(A0)+,D3
ADD.L
ADD.L
ADD.L
D0,D3
D1,D3
D2,D3
MOVE.L
ADD.L
ADD.L
#NUMERO,A1
D6,A1
#1,A1
MOVE.L
ADD.L
#PATRON,A3
D6,A3
MOVE.B
CLR.L
MOVE.L
#1,(A3)
D4
#SIMBOLOS_DER,A2
CMP.W
BEQ
#$0A,(A2)
MAL
CMP.W
BEQ
ADD.B
CMP.B
BNE
(A2)+,D3
LOCALIZADO2
#1,D4
#10,D4
OTRA2
; Comparamos con los d�gitos del
; alfabeto A.
MOVE.B
CLR.L
MOVE.L
CMP.W
BEQ
ADD.B
CMP.B
BNE
#2,(A3)
D4
#SIMBOLOS_IZQB,A2
(A2)+,D3
LOCALIZADO2
#1,D4
#10,D4
OTRA3
; Alfabeto "B"
MOVE.B
BRA
#10,(A1)
SAL
LOCALIZADO2 MOVE.B
D4,(A1)
SAL
ADD.L
#1,D6
CMP.W
BNE
#6,D6
AGAIN
MOVE.L
CLR.L
CLR.L
CLR.L
CLR.L
CLR.L
CLR.L
#PATRON,A2
D0
D1
D2
D3
D4
D5
MOVE.B
MOVE.B
MOVE.B
MOVE.B
MOVE.B
MOVE.B
MULU
MULU
MULU
MULU
ADD.L
ADD.L
ADD.L
ADD.L
(A2)+,D0
(A2)+,D1
(A2)+,D2
(A2)+,D3
(A2)+,D4
(A2)+,D5
#10000,D1
#1000,D2
#100,D3
#10,D4
D4,D5
D3,D5
D2,D5
D1,D5
MOVE.L
#NUMERO,A1
CLR.L
MOVE.L
OTRA4
CMP.W
BEQ
ADD.B
CMP.B
BNE
MOVE.B
BRA
LOCALIZADO3 MOVE.B
ADIOS
RTS
D4
#ESCONDIDO,A2
(A2)+,D5
LOCALIZADO3
#1,D4
#10,D4
OTRA4
#10,(A1)
ADIOS
D4,(A1)
; Alfabeto "A"
; Comparamos con los d�gitos del
; alfabeto B.
; **********************************
******************************************************************************
DECOD_DER
******************************************************************************
* Convierte un conjunto de siete bits a un digito, de acuerdo al alfabeto de* finido para la PARTE DERECHA del c�digo de barras (formato EAN-13).
* Recibe en A0 un puntero al primer elemento de la matriz del area derecha.
******************************************************************************
AGAINB
*
*
*
*
*
*
*
*
MOVE.L
CLR.L
CLR.L
CLR.L
CLR.L
#7,D6
D0
D1
D2
D3
MOVE.B
MULU
MOVE.B
MULU
MOVE.B
MULU
MOVE.B
(A0)+,D0
#1000,D0
(A0)+,D1
#100,D1
(A0)+,D2
#10,D2
(A0)+,D3
1323
CLR.L
ADD.B
ADD.B
ADD.B
ADD.B
CMP.B
BEQ
D5
D0,D5
D1,D5
D2,D5
D3,D5
#7,D5
TODO_OK
; Es el s�ptimo n�mero.
******************************************************************************
*
*
*
*
*
CMP.B
BEQ
CMP.B
BEQ
BRA
#6,D5
CORREGIR
#8,D5
CORREGIR
TODO_OK
*
*
ADD.L
ADD.L
D2,D0
D3,D1
*
*
NB
53
*
*
*
*
CLR.L
MOVE.B
MULU
ADD.W
D2
D1,D2
#$100,D0
D0,D2
*
*
*
*
CMP.W
CMP.W
CMP.W
CMP.W
#$0503,D2
#$0303,D2
#$0404,D2
#$0402,D2
*
*
*
*
CMP.W
CMP.W
CMP.W
CMP.W
#$0305,D2
#$0105,D2
#$0206,D2
#$0204,D2
*CORREGIR
; En D0 el n� de bits de las negras.
; En D1 el n� de bits de las blancas.
******************************************************************************
TODO_OK
OTRA
ADD.L
ADD.L
ADD.L
D0,D3
D1,D3
D2,D3
MOVE.L
ADD.L
#NUMERO,A1
D6,A1
CLR.L
MOVE.L
CMP.W
BEQ
ADD.B
CMP.B
BNE
MOVE.B
BRA
D4
#SIMBOLOS_DER,A2
(A2)+,D3
LOCALIZADO
#1,D4
#10,D4
OTRA
#10,(A1)
SALB
LOCALIZADO MOVE.B
D4,(A1)
SALB
#1,D6
#13,D6
AGAINB
ADD.L
CMP.W
BNE
RTS
; Comparamos con los d�gitos del alfabeto.
; ***********************************
******************************************************************************
CHECKSUM
******************************************************************************
*
******************************************************************************
MOVE.L
#NUMERO,A0
CLR.L
CLR.L
CLR.W
D0
D1
D2
REPITE2
MOVE.B
CMP.B
BEQ
(A0),D6
#$0A,D6
FALLO
ADD.B
(A0)+,D0
MOVE.B
CMP.B
BEQ
(A0),D6
#$0A,D6
FALLO
ADD.B
ADD
CMP
BNE
(A0)+,D1
#1,D2
#6,D2
REPITE2
MULU
ADD.L
#3,D1
D1,D0
DIVU
SWAP
#10,D0
D0
CLR.L
D1
CMP.W
BEQ
#0,D0
SALIR
REPITE
ADD.B
ADD.B
CMP.W
BNE
#1,D0
#1,D1
#10,D0
REPITE
SALIR
ADD.B
SUB.B
#$30,D1
#$30,D1
MOVE.L
ADD.L
MOVE.B
#NUMERO,A0
#12,A0
(A0),D3
CMP.B
BEQ
D1,D3
OK
PRINT
MOVE.W
RTS
MSG01
#0,LEYO_BIEN
MOVE.W
PRINT
RTS
#1,LEYO_BIEN
MSG00
FALLO
OK
******************************************************************************
BIG_NUMS
******************************************************************************
*
******************************************************************************
#BIG_NUMS1,A1
D6
CLR.L
CLR.L
MOVE.B
D5
D0
(A0)+,D0
ASL.L
MOVE.L
ADD.L
PINTA
PINTA
PINTA
PINTA
#2,D0
A1,A2
D0,A2
(A2)+
(A2)+
(A2)+
#$20
REPEAT2
REPEAT
MOVE.L
CLR.L
CMP.W #0,D5
BEQ ESPACIO
CMP.W #6,D5
BNE NO_ESPACIO
ESPACIO
PINTA $20
PINTA $20
NO_ESPACIO
ADD.W
CMP.W
BNE
#1,D5
#13,D5
REPEAT
SUB.L
#13,A0
CMP.W
BEQ
#2,D6
ULTIMA_NO_RETORNO
PINTA
PINTA
ULTIMA_NO_RETORNO
ADD.L
ADD.W
CMP.W
BNE
RTS
#$0D
#$0A
#43,A1
#1,D6
#3,D6
REPEAT2
; Espacio.
; Dejamos un espacio para agrupar
; los n�meros.
******************************************************************************
ORG
CODIGO
******************************************************************************
MOVE.L
#STACK,A7
; Inicializa el Stack
REPITE_TODO
PRINT
MSG02
SYSCALL
BEQ
INSTAT
ESPERA
MOVE.L
MOVE.W
#$EF0000,A0
(A0),D0
MOVE.W
#0,LEYO_BIEN
MOVE.L
MOVE.L
MOVE.W
#0,VEZ
#0,CUENTA
#0,GLOBAL
ESPERA
; Hacemos el RESET de la interrupt.
*BRA TESTING
MOVE.L
MOVE.L
MOVE.L
MOVE.L
#$100,A0
#$500,A1
; Parcheo de los vectores de interrupt.
; Vector 64.
(A0),BACKUP0
(A1),BACKUP1
MOVE.L
MOVE.L
#INT,(A0)
#INT,(A1)
; ...y actualizamos 'ambas' tablas.
BSR
AND.W
PIT_INIT
#$F1FF,SR
; Interrupciones habilitadas.
BSR
PIT_START
; En marcha el reloj.
INF
CMP.L
BGT
BRA
#59,CUENTA
FIN
INF
; EAN-13 = 60 barras blancas/negras.
FIN
OR.W
PINTA
DDD
#$0600,SR
#'.'
CLR.L
D0
ADD.L
MOVE.L
CMP.L
BNE
#1,D0
(A0),D3
#65000,D0
DDD
PINTA
PINTA
#$0D
#$0A
PRINT
PRINT
PRINT
PRINT
LINEA1
LINEA2
LINEA3
LINEA41
MOVE.L
MOVE.L
#$0,CUENTA
#$7006,D1
; Interrupciones deshabilitadas.
; Bucle para perder tiempo y desesti; mar interrupciones anteriores.
TESTING
********* ADD.L
#4,D1 ***************************************************
BSR
PINTA
ADD.L
BSR
PINTA
ADD.L
BSR
MATRIX_OUT
#'�'
#4,D1
MATRIX_OUT
#'�'
#4,D1
MATRIX_OUT
PRINT
LINEA42
ADD.L
#4,D1
BSR
PROCESA_SEIS
; Escribimos la ristra '101'
; Hasta ahora hemos imprimido el codigo '101' y la zona IZQUIERDA del c�digo.
ADD.L
#4,D1
PRINT
PRINT
LINEA11
LINEA121
BSR
PINTA
ADD.L
BSR
PINTA
ADD.L
BSR
PINTA
ADD.L
BSR
PINTA
ADD.L
MATRIX_OUT
#'�'
#4,D1
MATRIX_OUT
#'�'
#4,D1
MATRIX_OUT
#'�'
#4,D1
MATRIX_OUT
#'�'
#4,D1
; Escribimos la ristra '01010'
*
BSR
MATRIX_OUT
PRINT
PRINT
LINEA122
LINEA11
BSR
PROCESA_SEIS
ADD.L
#4,D1
PRINT
LINEA41
BSR
PINTA
ADD.L
BSR
PINTA
ADD.L
BSR
PRINT
MATRIX_OUT
#'�'
#4,D1
MATRIX_OUT
#'�'
#4,D1
MATRIX_OUT
LINEA42
; Escribimos la ristra '010'
PRINT
LINEA21
; Final.
BSR
PINTA
BSR
DECOD_IZQ
#$20
DECOD_DER
; Espaciooo...
BSR
CHECKSUM
MOVE.L
BSR
#NUMERO,A0
BIG_NUMS
CMP.W
BNE
*
#1,LEYO_BIEN
REPITE_TODO
MOVE.L
MOVE.L
#$100,A0
#$500,A1
MOVE.L
MOVE.L
; Parcheo de los vectores de interrupt.
; Vector 64.
BACKUP0,(A0)
BACKUP1,(A1)
SYSCALL
RETURN
*************************AREA DE PILA*****************************************
DS
1024
; Reservamos 1 Kb para el Stack
STACK
*************************AREA DE VARIABLES************************************
ORG
DATOS
MATRIX
RISTRA
GLOBAL
CUENTA
VEZ
PATRON
DS
DS
DC.W
DS
DS
DS
300
100
$0000
4
2
6
NUMERO
DS
MSG00
DC.B
MSG01
DC.B
MSG02
DC.B
S_MILISGS DS
S_REBASES DS
S_TIEMP2 DC.B
CADENA
DS
COCIENTE DS
S_NUMADD DS
PARES
DC.W
LEYO_BIEN DC.W
BACKUP0 DS 4
BACKUP1 DS 4
SIMBOLOS_DER
_SIMBOLS_DER
50
21,'Checksum correcto. ',$0D,$0A
21,'Lectura no v�lida. ',$0D,$0A
59,'Por favor, coloca el sensor en blanco y pulsa una tecla. ',$0D,$0A
10
10
11,' segundos. '
14
14
10
00
$0000
DC.W
DC.W
3211, 2221, 2122, 1411, 1132
1231, 1114, 1312, 1213, 3112
* SIMBOLOS_DER = SIMBOLOS_IZQA *
SIMBOLOS_IZQB DC.W
_SIMBOLS_IZQB DC.W
CORRECT1 DC.W
_CORRECT1 DC.W
ESCONDIDO
_ESCONDID
BARRA1
BARRA2
BIG_NUMS1
BIG_NUMS2
BIG_NUMS3
LINEA1
LINEA2
LINEA3
LINEA41
LINEA42
LINEA51
1123, 1222, 2212, 1141, 2311
1321, 4111, 2131, 3121, 2113
$0403, $0403, $0403, $0205, $0403
$0403, $0205, $0205, $0205, $0403
DC.W
DC.W
60,'
�
60,'
�
'��� ��
'� � �
'��� ���
DC.B
DC.B
DC.B
DC.B
DC.B
DC.B
DC.B
DC.B
DC.B
DC.B
DC.B
11111, 12122, 12211, 12221, 21122
22112, 22211, 21212, 21221, 22121
� �� �
� � �
�
��� ��� � � ���
��� ��� ��� ���
��� ���
� ���
�� ���
� � �� � �� �
� �
��� ��� ��� ���
'
��� ��� ��� ���
'
���
� ���
� ���'
� ��� � �� � �',$d,$a
� �',$d,$a
80,'������������������������������������������������ Ancho Relativo �����������Ŀ ',$00
80,'� Pr. 3 �BAR_1�BAR_2�BAR_3�BAR_4�BAR_5�PATRN�BAR1�BAR2�BAR3�BAR4�CODIF. �n�� ',$00
80,'���������������������������������������������������������������������������� Ĵ ',$00
11,'�C�d."101"�'
52,'�
�
�
�
�
�
�
�
� �',$0D,$0A,$00
11,'�D�git.01 �'
LINEA52
LINEA11
LINEA121
LINEA122
LINEA20
LINEA21
11,'
� �'
80,'���������������������������������������������������������������������������� Ĵ ',$00
11,'�"01010" �'
40,'�
�
�
�
�
�
� � '
80,'�C�d."101"�
�
�
�
�
�
�
�
�
�
�
� � ',$00
80,'������������������������������������������������������������������������������ ',$00
DC.B
DC.B
DC.B
DC.B
DC.B
DC.B
******************************************************************************
* DRIVER PARA GESTION DE LA PIT **********************************************
******************************************************************************
BASE_PIT EQU
$FE0001
; Registros de la PI/T.
TCR
EQU
BASE_PIT+32
TIVR
EQU
BASE_PIT+34
CPR
EQU
BASE_PIT+36
CR
EQU
BASE_PIT+44
TSR
EQU
BASE_PIT+52
PIT_INIT
MOVE.W
MOVE.B
MOVE.B
MOVE.L
MOVE.L
MOVEP.L
MOVE.L
MOVE.L
MOVE.L
MOVE.L
RTS
PIT_TIME MOVE.W
MOVE.L
RTS
PIT_STOP BCLR.B
RTS
PIT_START BSET
RTS
RELOJ
BCLR.B
BSET.B
ADDQ.W
RTE
REBASES
DS
SALTO0
INT2STR
MOVE.L
SYSCALL
RTS
#$0,REBASES
#%10100110,TCR
#$41,TIVR
#250000,D0
#CPR,A0
D0,(A0)
#$104,A0
#$504,A1
#RELOJ,(A0)
#RELOJ,(A1)
; 1/8MHz*(32_del_preesc.)*250000=1 s.
; Parcheo de los vects. de interrupt.
; Vector "FIRST USER INT. VECTOR"
; ...y actualizamos 'ambas' tablas.
REBASES,4(A7)
#CR,6(A7)
#0,TCR
; Paramos el reloj.
#0,TCR
; Reloj en marcha.
#0,TSR
#0,TSR
#$01,REBASES
; Llegamos aqu¡ si el contador de la
; PIT se ha desbordado.
2
; Veces que se desborda el contador.
S_MILISGS
#S_MILISGS,-(A7)
WRITE
*���������������������������������������������������������������������������� Ŀ
*�
� ANCHO RELATIVO
�CODIFICAC.�
*���������������������������������������������������������������������������� Ĵ
*���������������������������������������������������������������������������� Ĵ
*
*������������������������������������������������ Ancho Relativo �����������Ŀ
*� Pr. 3 �BAR_1�BAR_2�BAR_3�BAR_4�BAR_5�PATRN�BAR1�BAR2�BAR3�BAR4�CODIF. �n��
*���������������������������������������������������������������������������� Ĵ
*�C�d.'101'�1410 �713 �1035 �
�
�
�
�
�
�
�
� �
*�D�git.01 �2893 �1239 �3985 �6543 �
�1000 �1.34�1.23�2.34�4.53�0111010�1a�
*�D�git.02 �2893 �1239 �3985 �6543 �
�1000 �1.34�1.23�2.34�4.53�1110101�2a�
*�D�git.03 �2893 �1239 �3985 �6543 �
�1000 �1.34�1.23�2.34�4.53�1110101�3b�
*�D�git.04 �2893 �1239 �3985 �6543 �
�1000 �1.34�1.23�2.34�4.53�0111010�4b�
*�D�git.05 �2893 �1239 �3985 �6543 �
�1000 �1.34�1.23�2.34�4.53�1110101�2a�
*�D�git.06 �2893 �1239 �3985 �6543 �
�1000 �1.34�1.23�2.34�4.53�0111010�8b�
*���������������������������������������������������������������������������� Ĵ
*�'01010' �1410 �713 �1035 �1035 �895 �
�
�
�
�
�
� �
*���������������������������������������������������������������������������� Ĵ
*�D�git.07 �2893 �1239 �3985 �6543 �
�1000 �1.34�1.23�2.34�4.53�1110101�3 �
*�D�git.08 �2893 �1239 �3985 �6543 �
�1000 �1.34�1.23�2.34�4.53�0111010�4 �
*�D�git.09 �2893 �1239 �3985 �6543 �
�1000 �1.34�1.23�2.34�4.53�1110101�8 �
*�D�git.10 �2893 �1239 �3985 �6543 �
�1000 �1.34�1.23�2.34�4.53�1110101�1 �
*�D�git.11 �2893 �1239 �3985 �6543 �
�1000 �1.34�1.23�2.34�4.53�0111010�3 �
*�D�git.12 �2893 �1239 �3985 �6543 �
�1000 �1.34�1.23�4.34�4.53�1110101�9 �
*�C�d.'101'�1410 �713 �1035 �
�
�
�
�
�
�
�
� �
*������������������������������������������������������������������������������
* Si se alteran DOS bits en direcciones opuestas, el s�mbolo ser�a v�lido,
*
pero el checksum permitir�a DETECTAR el problema.
* Si en un s�mbolo se altera UN bit, el s�mbolo deja de ser v�lido, por lo que
*
el fallo ha sido DETECTADO. �Es posible corregirlo?
*
-> Si solo se ha estropeado UN bit de UN s�mbolo, es posible solucionarlo
*
facilmente con el caracter de checksum.
Descargar