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 Gutirrez. * 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.