14 marzo 2012

DESCIFRAR TRAMA DE COMUNICACIÓN CCTALK

(EN) Decrypting cctalk communication frame. An example.
(FR) Décrypter trame de comunication cctalk. Un exemple.
(PT) Decifrar comunicação cctalk. Um exemplo.  
---------------------------------------------------------------------------------------------------------------------------------

PARA REPASAR: Si queréis podéis revisar otras entradas anteriores sobre el tema: El adaptador para conectar el bus ccTalk al pc y como obtuve los códigos que voy a intentar entender...
Sobre hopper Azkoyen buscando en la web por "protocolo cctalk hopper u-ii". 
Sobre selector de monedas buscando por "modular x6 cctalk".

Voy a tratar de interpretar los códigos ccTalk que he obtenido y mostrado en la entrada anterior.

Exponemos como resumen unas ideas a tener claras:
La comunicación con el protocolo ccTalk es half duplex y asíncrona. Las señales son como el RS232 pero con niveles de tensión TTL (5v para un 1 lógico, y 0v para un 0 lógico). Comúnmente 9600 baudios, 1 bit de start, 8 bits de datos, sin paridad y 1 bit de stop. El bus ccTalk sólo tiene una linea de datos. Que con el adaptador al pc, entrarán (se leerán) por Rx y saldrán (se transmiten) por Tx, pero en el bus cctalk estarán todos en la misma linea DATA. Ningún dispositivo cctalk enviará nada a la linea DATA si no se le ordena antes por el maestro. Todos estarán en modo "lectura" y "calladitos" hasta que toque responder a lo que la unidad central maestra mande. Momento éste, en que la unidad central, permanecerá "en silencio" y a la escucha de la respuesta.

La forma y estructura de un mensaje cctalk estándar es la siguiente:
[Dirección de destino] [Número de bytes de datos] [Dirección de origen] [Cabecera u orden] [Dato1] [Dato2]...[Dato N] [Checksum]
(También hay mensajes encriptados y con control de redundancia cíclica de 16 bits, pero aún no me he peleado con ellas)
Cada secuencia de comunicación mínima consta de dos tramas según este formato. Primero desde el maestro, indicándole algo al esclavo, y luego, la respuesta del esclavo. Si el esclavo no contesta se considerará un error y el maestro repetirá el  intento. Una comunicación correcta requiere de envío y respuesta.

[DIRECCIÓN DE DESTINO] Indica a que dispositivo va dirigido el mensaje. Pueden ser desde la 0 a la 255. Algunas son especiales. La 0 afecta a todos los dispositivos, a modo de llamada general, todos se dan por enterados. La 1 es siempre la dirección del control o dispositivo maestro. Desde la 2 a la 255 corresponde una a cada dispositivo. No debe de haber dos dispositivos en el mismo bus con la misma dirección. Ésta se configura por switches o por comandos. Aunque, esto ya no es obligatorio, dispositivos como un selector de monedas suele ser la dirección 2, y los pagadores 3, 4, y 5.

[NÚMEROS DE BYTES DE DATOS] Este byte indica el número de Datos (N) del mensaje. Si es 0, el mensaje no envía datos y el número total de bytes será cinco (dirección mensaje, nº de datos, dirección origen, cabecera, y checksum).


[DIRECCIÓN DE ORIGEN] Indica "quien" envía este mensaje.

[CABECERA] Cada número indica una orden específica a la que el dispositivo obedecerá. Hay algunas especiales: 0 ACK incida que el dispositivo ha realizado correctamente el comando; 5 NACK por algún error el comando no se ha realizado; 6 BUSY el dispositivo en cuestión está ocupado, y no puede obedecer en este momento.

[DATOS] Puede ser cualquier byte entre 0 y 255 y el significado dependerá del comando a ejecutar.

[CHECKSUM] Para comprobar que no ha habido errores se suman todos los bytes del mensaje (incluido el de checksum) y la suma deberá ser tal que los últimos 8 bits del resultado sea 0. (00 en hexadecimal)


------------------------------------------------------------------------------------------------------------------------------

Sabido lo anterior veamos qué conseguimos descifrar de la trama conseguida en su día y expuesta en una entrada anterior. Recordar que durante la trama se ha introducido una moneda de 2 euros, la máquina ha devuelto 1euro y 80 céntimos (1euro + 4 de 0.20euros) y ha jugado un crédito.
Los códigos están en hexadecimal.
El primer problema es saber en donde empieza la verdadera "conversación". Alguna lectura inicial puede ser fruto de picos de encendido de la máquina, los dispositivos ccTalk no hacen caso hasta que pase un tiempo desde que son alimentados (250 ms algún selector de azkoyen, 200 ms algún hopper...)

La primera ristra de datos es: FE 00 04 00 01 EC OF 01 01 04 00 00 FA 05 00 01 ...
Sabemos que han de ser como mínimo 5 bytes y todos juntos han de sumar un número que acabe en 00 en hexadecimal. Además el primer mensaje debería tener como dirección de origen a la máquina de control(01). El primer 01 en la tercera posición nos forma el mensaje 04 00 01 EC 0F cuyos bytes suman 100h. Olvidémonos entonces de FE 00 y comencemos con:
-------------------------

04 00 01 EC 0F
Para el dispositivo 04, se envían 00 datos, desde la cpu 01, con la orden EC (236 en decimal, LECTURA ESTADO DE OPTOS), y la suma de verificación 0F
Y la contestación:
01 01 04 00 00 FA
Para la cpu 01, se envía 01 dato, desde el dispositivo 04 (probablemente un hopper), con cabecera 00 (es una contestación de conformidad), el dato es 00 (00000000 en binario), y la suma de verificación o checksum FA.
Supongo un pagador de Azkoyen, que es del que he encontrado información en internet.
Analizando el dato: El bit0, menos significativo, corresponde al optoacoplador que detecta si el pagador está vacío (0 si está cortado el haz con monedas y uno si nada obstruye la luz del diodo emisor al receptor). El bit1 indica si el pagador está lleno. Los otros bits del 2 al 7 no se usan. Así que el dato devuelto podría ser: 00h=00000000b (hopper lleno de monedas), 02h=00000010b (hopper a media carga), y 03h=00000011b (hopper vacío). Una contestación de dato 01h=00000001b sería que está activo el sensor de vacío, por lo tanto vacío, pero al mismo tiempo cortado el haz del opto de lleno y por tanto lleno. El hopper o pagador no puede estar lleno y vacío al mismo tiempo y debería ser considerado por la cpu un error.
El caso que nos ocupa, el dato devuelto es 00, por lo tanto el hopper 04 está lleno o "¡no tiene optos!"
Luego se repiten la pregunta y respuesta para los dispositivos 05 y el 03 (que también suelen ser pagadores):
05 00 01 EC 0E---------01 01 05 00 00 F9 
03 00 01 EC 10---------01 01 03 00 00 FB
Y vemos, por la respuesta 00, que también llenos.
 ------------------------

03 00 01 A3 59-----------01 01 03 00 80 7B
Para el hopper 03, 0 datos, desde la cpu, A3 (163 en decimal, TEST HOPPER), y checksum.
El comando A3h=163d provoca el envío de información acerca de varios flags de error y operación del hopper. Los flags guardan información desde la última vez que se preguntaron, pasan la información y se reinicializan. Sólo envía un dato por lo que debe de tratarse de un hopper UII cctalk standard. Existe el hopper UII cctalk PLUS que respondería con dos datos.
Siendo 1=cierto y 0=falso, analizamos el dato  devuelto:
El bit0 indica corriente máxima absoluta excedida. El bit1 tiempo máximo de pago excedido. El bit2, motor girando en sentido contrario durante el último pago para eliminar un atasco. El bit3, intento de fraude de fotocélula, salida bloqueada durante el reposo. Sensor de moneda no detectado. El bit4, intento de fraude de fotocélula, detección de moneda en reposo. El bit5, fotocélula bloqueada permanentemente durante el pago. El bit6, no se utiliza. El bit7, pago inhabilitado.
Para la cpu 01, se devuelve 01 dato, desde el hopper 03, correctamente 00: el 80h=10000000b. Así que el hopper 03 le contesta a la cpu que tiene el pago inhabilitado.
------------------------

04 00 01 EC 0F---------01 01 04 00 00 FA
Vuelve a hacer una "lectura de estado de optos" del hopper 04 y éste le responde lo mismo

04 00 01 A3 58----------01 01 04 00 80 7A
Y un "test de hopper" 04 que también contesta: "inhabilitado".
-----------------------

05 00 01 EC 0E----------01 01 05 00 00 F9
03 00 01 EC 10-----------01 01 03 00 00 FB
05 00 01 A3 57-----------01 01 05 00 80 79
03 00 01 A3 59-----------01 01 03 00 80 7B
Y lo mismo con los hoppers 5 y 3.
-----------------------

(...)
Luego se pasa un buen rato haciendo lo mismo. Mientras no pasa nada chequea los hoppers continuamente.Ya en el siguiente bloque de la foto encontramos, en la quinta linea algo nuevo.

05 00 01 F2 08
Para el hopper 5, sin datos, ordenado por la cpu (01), orden F2 (242decimal=PETICIÓN Nº DE SERIE), y checksum.
Cada hopper tiene un número de serie de fábrica. Este número será necesario saberlo para ordenar un pago de monedas.
01 03 05 00 6B 8F 12 EB
El hopper 5 contesta a la cpu con tres datos que forman el número de serie. El primer dato es el menos significativo, y el tercero el más. Así que el número de serie es: 128F6Bhexadecimal=1216363decimal 
---------------------------

 05 00 01 A6 54----------01 04 05 00 00 00 00 00 F6
Para hopper 5, sin datos, la cpu (01), ordena A6(166decimal=CONSULTA DEL ESTADO DEL HOPPER), y checksum.
Para la cpu(01), con 4 datos, el hopper 5, responde (00): 
El primer dato serán los pagos hechos desde el último reset (del valor FFh=255d se pasa al 1, de manera que un 0 es que no se ha pagado nada desde un reset). El segundo dato será las monedas pendientes de pagar. El tercero, el número de monedas pagadas en el último pago (éste si estuviésemos pagando). Y el cuarto, el número de monedas pendientes de pagar en un pago anterior. La información se guarda en la EPROM del hopper aunque falle la alimentación. Podremos recuperar la información al reiniciar el pagador. Tras un reset los cuatro datos se ponen a cero. Este es nuestro caso aquí.
------------------------------- 

05 01 01 A4 A5 B0----------01 00 05 00 FA
Para el hopper 05, se le da un dato, desde la cpu(01), la orden A4(164decimal=HABILITAR HOPPER), el dato es A5, y el checksum. El comando A4h(164d) se debe utilizar para habilitar el pagador antes de pagar monedas con cualquier orden de pago. Si el dato que se envía es A5h se habilita el hopper. Si es distinto de A5 el hopper estará deshabilitado.
La segunda secuencia es el hopper que contesta, a la cpu, que la orden ha sido realizada con éxito (00).
----------------------------------

05 04 01 A7 6B 8F 12 01 42----------01 00 05 00 FA
Para el hopper 5, cuatro datos, desde la cpu(01), la orden A7h(167d PAGAR MONEDAS CON HOPPER). De los cuatro datos, los tres primeros datos son el número de serie que nos facilitó el comando F2, y que son necesarios para construir esta orden A7 y que el hopper pague la cantidad de monedas que indica el cuarto dato. En este caso una moneda.
Si se puede hacer el pago el hopper devuelve una trama de aceptación como en este caso y comienza a efectuar el pago hasta que extraiga todas las monedas indicadas, se detecte un vano máximo, se reciba una orden de cancelación, se detecte un error, o haya un reset o fallo de alimentación.
Si no se puede pagar por un error, porque el hopper esté ocupado con otra orden, o el código (nºserie) no sea correcto, éste devolverá una trama de reconocimiento negativo.
-------------------------------------

03 00 01 EC 10----------01 01 03 00 00 FB
Vuelve a hacer lectura de optos del hopper 3, e indica hopper lleno.
-------------------------------------

05 00 01 A6 54----------01 04 05 00 01 01 00 00 F4
Después de ordenar el pago, se hace un seguimiento de este. Esta trama vuelve a pedir una A6h(166d CONSULTA DEL ESTADO DEL HOPPER). 01 pago ordenado desde el último reset (éste). 01 moneda pendiente de pagar. 00 monedas pagadas en este pago (así que no ha realizado todavía el pago ordenado) y 00 monedas pendientes de pagos anteriores.
Así que debe de estar pagando. Sigamos controlándolo.
--------------------------------------

05 00 01 A6 54----------01 04 05 00 01 01 00 00 F4
Seguimos como estábamos, pendiente de pagar una moneda el hopper 5.
---------------------------------------

04 00 01 A3 58----------01 01 04 00 80 7A
Se chequea el hopper 4 (A3h=163d=TEST HOPPER) y el hopper contesta. Pago deshabilitado.
---------------------------------------

04 00 01 EC 0F----------01 01 04 00 00 FA
Lectura del estad de optos (ECh=236d). Hopper 4 lleno de monedas.
---------------------------------------


05 00 01 A6 54----------01 04 05 00 01 01 00 00 F4      (dos veces)
Y seguimos pendientes del pago de una moneda del hopper 5.
--------------------------------------

03 00 01 EC 10----------01 01 03 00 00 FB
Lectura del estado de optos (ECh=236d). Hopper 3 lleno de monedas.
--------------------------------------

05 00 01 A6 54----------01 04 05 00 01 01 00 00 F4
03 00 01 A3 59----------01 01 03 00 80 7B
05 00 01 A6 54----------01 04 05 00 01 01 00 00 F4
04 00 01 EC 0F---------01 01 04 00 00 FA
05 00 01 A6 54----------01 04 05 00 01 01 00 00 F4    (dos veces)
04 00 01 A3 58----------01 01 04 00 80 7A
03 00 01 EC 10----------01 01 03 00 00 FB
05 00 01 A6 54----------01 04 05 00 01 01 00 00 F4
Chequeando continuamente los hoppers sin novedades....
---------------------------------------

05 00 01 A6 54----------01 04 05 00 01 00 01 00 F4
Aquí hay un cambio en la respuesta. Los datos de respuesta del estado del hopper 5, que hasta ahora eran siempre 01 01 00 00, en este mensaje pasan a ser 01 00 01 00. Ya no hay monedas pendientes de pagar, y en el último pago se pagó una moneda. Por fin, el hopper 5 nos indica que ha pagado una moneda.
----------------------------------------

05 00 01 F2 08----------01 03 05 00 6B 8F 12 EB
La cpu vuelve a consultar el número de serie del hopper 5.
----------------------------------------

04 00 01 EC 0F----------01 01 04 00 00 FA
El hopper 4 sigue lleno.
----------------------------------------

05 01 01 A4 00 55----------01 00 05 10 FA
Se deshabilita el pago del hopper 5.
----------------------------------------

05 00 01 EC 0E----------01 01 05 00 00 F9
03 00 01 A3 59----------01 01 03 00 80 7B
Más chequeos del estado de los hoppers.
-----------------------------------------

03 00 01 F2 0A----------01 03 03 00 2B 90 0E 30
Consulta del número de serie del hopper 3. Este es 0E902Bh=954411d.
-----------------------------------------

03 00 01 A6 56----------01 04 03 00 00 00 00 00 F8
Consulta del estado del hopper 3. Sin pagos realizados ni pendientes desde el reset.
----------------------------------------

03 01 01 A4 A5 B2----------01 00 03 00 FC
Habilitar el hopper 3 para pagos.
-----------------------------------------

03 04 01 A7 2B 90 0E 01 87----------01 00 03 00 FC
Que el hopper 3 pague una moneda.
----------------------------------------

05 00 01 A3 57----------01 01 05 00 80 79
Y seguimos revisando fotocélulas del hopper 5.
----------------------------------------

03 00 01 A6 56-----------01 04 03 00 01 01 00 00 F6
Y también se sigue revisando como va el pago del hopper 3. Pendiente de pagar una moneda de una orden de pago.
----------------------------------------

04 00 01 EC 0F----------01 01 04 00 00 FA
03 00 01 A6 56----------01 04 03 00 01 01 00 00 F6
04 00 01 A3 58----------01 01 04 00 80 7A
05 00 01 EC 0E----------01 01 05 00 00 F9
03 00 01 A6 56----------01 04 03 00 01 01 00 00 F6  (tres veces)
04 00 01 EC 0F----------01 01 04 00 00 FA
03 00 01 A6 56----------01 04 03 00 01 01 00 00 F6
05 00 01 EC 0E----------01 01 05 00 00 F9
05 00 01 A3 57----------01 01 05 00 80 79
03 00 01 A6 56----------01 04 03 00 01 01 00 00 F6  (dos veces)
04 00 01 A3 58----------01 01 04 00 80 7A
03 00 01 A6 56----------01 04 03 00 01 01 00 00 F6
04 00 01 EC 0F----------01 01 04 00 00 FA
03 00 01 A6 56----------01 04 03 00 01 00 01 00 F6
Hasta aquí ha estado chequeando continuamente los hoppers y el pago del hopper 3. Aquí, por fin, el hopper 3 confirma que ha pagado una moneda.
------------------------------------------------------------

03 00 01 f2 0A----------01 03 03 00 2B 90 0E 30
La cpu consulta el número de serie del hopper 3 que es 0E902Bh=954411d.
-------------------------------------------------

05 00 01 EC 0E----------01 01 05 00 00 F9
03 00 01 A3 59----------01 01 03 00 00 FB
Vuelta a revisar el estado de los hoppers.
--------------------------------------------

03 00 01 F2 0A----------01 03 03 00 2B 90 0E 30
03 00 01 A6 56----------01 04 03 00 01 00 01 00 F6
03 01 01 A4 A5 B2----------01 00 03 00 FC
03 04 01 A7 2B 90 0E 03 85----------01 00 03 00 FC
03 00 01 A6 56----------01 04 03 00 02 03 00 00 F3
Vuelve a habilitar el pago del hopper 3, pero esta vez (segundo pago) le manda pagar 3 monedas.
Obsérvese que parece seguir siempre el mismo procedimiento.
1º pedir el nºde serie del hopper F2
2º observar el estado del pago A6
3º habilitar el hopper para pagar A4
4º ordenar el pago A7
5º estar pendiente del pago A6
6º y cuando finalmente se ha pagado inhabilitar el hopper para el pago A4
---------------------------------------------

04 00 01 A3 58----------01 01 04 00 80 7A
03 00 01 A6 56----------01 04 03 00 02 03 00 00 F3
04 00 01 EC 0F----------01 01 04 00 00 FA
05 00 01 A3 57----------01 01 05 00 80 79
Se sigue revisando. Hasta aquí nada nuevo.
-----------------------------------------------

03 00 01 A6 56----------01 04 03 00 02 02 01 00 F3
Aquí cambia algo la cosa. Es el segundo pago. Ya solo tiene 2 monedas pendientes de pago, porque ha pagado 1 y no debe nada de ningún pago anterior. Vemos que el hopper está pagando.
---------------------------------------------

05 00 01 EC 0E----------01 01 05 00 00 F9
03 00 01 A6 56----------01 04 03 00 02 01 02 00 F3
En este segundo pago del hopper 3 ya ha pagado 2 monedas y queda 1 por pagar.
--------------------------------------------



03 00 01 A6 56----------01 04 03 00 02 01 02 00 F3
03 00 01 A6 56----------01 04 03 00 02 00 03 00 F3
Se han pagado las tres monedas y no quedan pendientes.
--------------------------------------------

03 00 01 F2 0A----------01 03 03 00 2B 90 0E 30
04 00 01 EC 0F----------01 01 04 00 00 FA
03 01 01 A4 00 57----------01 00 03 00 FC
Inhabilita el hopper 3 para pagos. Ya  hemos acabado de pagar.
---------------------------------------------

Y desde aquí hasta el final ya se pasa todo el tiempo chequeando el estado de los hoppers. La máquina ya ha pagado una moneda del hopper 5 y cuatro del hopper 3 (en dos veces 1+3).


Todo corresponde con lo que me esperaba, salvo que no he encontrado el código de comunicación con el selector de monedas. Y ya he comentado, que he introducido una moneda de 2euros. Esto me ha extrañado, pero después de revisar el esquema eléctrico de la máquina, me he encontrado con que, no todos los dispositivos van unidos al mismo bus cctalk, como pensaba. Sino que, en esta máquina, el selector de monedas tiene su línea de comunicación cctalk propia con la cpu, los hoppers otra diferente y el lector de billetes también la suya propia, todas independientes. Para hacer el monitorizado de la comunicación yo he conectado a la linea de los hoppers, por eso únicamente aparece comunicación de pagos.

De todas formas me queda constatado que las cosas funcionan como yo había entendido, y aquí queda un rollo curioso para el que le interese el asunto.
He revisado un par de veces lo que escrito. Esta entrada es un poco densa y espero no haber metido la pata. Pero como siempre, ya sabéis que no os debéis fiar a ciegas. Aunque trato de ser exacto, muchas veces cometo errores, como todo el mundo. Mi afán en este blog es aprender yo mismo. Así que si detectáis algún fallo, o algo importante que aportar, me encantarían comentarios o emails.
Saludos.



(CONTINÚA CON:Otra entrada sobre trama cctalk de un selector de monedas) 

03 febrero 2012

OBTENER TRAMAS CCTALK

(EN) Getting cctalk frames.
(FR) Obtenir trames cctalk.
(PT) Obter trama cctalk.
-----------------------------------------------------------------------------------------------------------------------------   

PARA REPASAR: En la web de Money Controls,  o buscando por cctalk.org puedes descargarte las especificaciones genéricas de como funciona el protocolo de comunicaciones serie ccTalk.

 Bueno, me he estado peleando algo más con esto del protocolo ccTalk. Hay una entrada anterior sobre este tema. En esta nueva entrada voy a tratar de presentar un poco más mis progresos. CCTalk es un protocolo de comunicación serie, hecho por personal de Money Controls, de baja velocidad, para control de redes de dispositivos, especialmente en la industria del tratamiento de monedas (selectores de monedas, pagadores, ...). Esto no impide que también se pueda usar para otras cuestiones que no requieran una velocidad en la transmisión de datos excesiva.
En mi afán de aprender a usar comunicación serie, me he interesado por este protocolo por dos cuestiones:
 a) ccTalk es un estándar abierto. En la web de Money Controls puedes descargarte las especificaciones generales del protocolo. Aunque ccTalk es marca registrada, permiten el uso sin pagar royaltis, ni obtener licencias.
 b) Hoy por hoy, tengo acceso a dispositivos de control de monedas, y por eso me resulta fácil hacer pruebas y experimentos. Se trata de un protocolo sencillo para aplicar con microcontroladores pequeños y de bajo coste. Y esto me parece ideal para aprender de forma autodidacta.

En esta ocasión he conseguido leer una trama real de datos de un bus cctalk de una máquina de apuesta de monedas. Y esto es lo que trataré de exponer en esta entrada. En alguna posterior a ver si me dedico a analizarla. Pero por si acaso alguien lo quiere ir haciendo expondré la trama y como he hecho para conseguirla. Ni que decir tiene, que estamos hablando de los datos que se transmiten por el bus para hacer interactuar a los diferentes dispositivos. No hablamos nunca de lo que la cpu de la máquina "piensa" o calcula para realizar el juego. Ni sé, ni pretendo, descubrir algoritmos ocultos, o secretos de empresa, ni trucos de juego. Me limito a intentar estudiar un protocolo abierto y público para conseguir usarlo.

Primero dejaremos constancia de algunas ideas básicas,de en que consiste la comunicación de un bus cctalk. Si te interesa ampliar. Todo está sacado de las especificaciones generales que puedes conseguir en inglés buscando por cctalk.org  y Money Controls. Actualmente, yo hablo del Issue 4.5. También puedes buscar algo por la red sobre dispositivos Azkoyen (selectores de monedas X6, Z6, hopper U-II, ...). Para mi, los dispositivos Azkoyen son los más conocidos, y con los cuales, es más fácil que pueda hacer pruebas. En España, está muy extendido su uso, pero el protocolo cctalk es compartido por muchos fabricantes.


Un bus de datos ccTalk consta únicamente de un hilo. La comunicación es serie, asíncrona y half-duplex. Sólo un dispositivo de todos puede estar transmitiendo en un momento dado. La forma de transmitir es idéntica al RS232 estándar, pero las tensiones no son de +15 a -15, sino con niveles TTL. Un uno lógico será +5v, y un cero lógico serán 0v. Y no usaremos las señales RTS,CTS,DTR,DCD,DSR. Solo nos interesan Rx y Tx que usarán este mismo único cable de datos para viajar. Los parámetros para la transmisión que usará ccTalk son: 9600 baudios, 1 bit de start, 8 bits de datos, sin paridad, 1 bit de stop. Puede haber una opción de velocidad más lenta a 4800 baudios, y hay nuevos dispositivos que intentan usar velocidades de puerto USB, pero el estándar son 9600 baudios.
La alimentación de los dispositivos necesita de dos cables más para la alimentación. La masa que será referencia también para los 0v del cable de DATOS. Y el positivo de la alimentación que suele ser +12v aunque hay dispositivos que van a 24v. 

Con estas ideas, a mi ya se me ocurrió lo siguiente. Hay una serie de integrados de Maxim: MAX202, ..., MAX232, que adaptan las tensiones (+15v a -15v) de un puerto serie común de un pc, a las tensiones TTL (0v y +5v). Así que podría conectar el pin de lectura del puerto serie del pc al cable de datos del bus cctalk, mediante este integrado, y manejando el puerto serie leer lo que sucede en el bus cctalk.
Luego me he encontrado con que el asunto pintaba más fácil todavía. En el manual de las especificaciones genéricas del ccTalk, publicadas por Money Controls ya se propone un circuito sencillo para conectar el pc al bus ccTalk. Usando un MAX232 en vez de un MAX202 porque es el que encontré, y añadiendo un 7805 para alimentar al circuito desde la alimentación más común de +12v de los dispositivos que conozco ccTalk, monté mi adaptador PC (RS232) a ccTalk según he comentado en su momento. (Copia el esquema y amplíalo si no lo ves demasiado bien en el blog).

El problema de "ojear" el puerto serie lo he resuelto buscando algún programa para escanear o monitorizar el puerto serie. Hay varios. El problema fue que me he limitado de momento a software shareware y demos, con lo que las posibilidades vienen lógicamente limitadas. He conseguido algo satisfactorio con el programa Docklight pero tiene la limitación de que no puedes guardar los datos. Así que para este primer intento cutre, me he limitado a sacar unas fotos a la pantalla de mi portátil, y luego recortar y pegar para quedarme con los datos que me interesaban.

Un esquema general de como he conectado para monitorizar el bus de una máquina tragaperras es el siguiente. He usado  una fuente de alimentación externa, para que no importe el consumo ni la tensión del adaptador PC-ccTalk. Así que es importante el interconexionar las masas para que el potencial 0v sea igual en el PC, la máquina tragaperras, y el adaptador cctalk-pc.

Una vez enchufado todo. Con el ordenador corriendo y monitorizando el puerto serie, enciendo la máquina tragaperras y arranca, introduzco una moneda de 2 euros, y espero a que me cambie (paga una moneda de 1 euro y cuatro de 20 céntimos), juego el crédito correspondiente a los 20 céntimos, me da opción de avances y saco un premio que luego pierdo por bonos para un juego superior. Durante todo esto he monitorizado y aparece en la foto.
No quiero aquí indicar de que máquina ni fabricante se trata, es irrelevante. Sólo saber que dispone, al menos, de selector de monedas, hoppers, y lector de billetes en un bus cctalk.
A continuación muestro la foto, en donde he recortado, de las diferentes fotos de la pantalla, todos los datos monitorizados y por orden. Es un poco chapuzero. Marca de estilo de este blog. Pero son los medios que se me han ocurrido dentro de los que podía disponer en el momento.
En una siguiente entrada espero explicar un poco como van las tramas ccTalk y las iré poniendo más ordenaditas.  De momento creo que la entrada se me empieza a hacer larga. Si no puedes ver la foto claramente, sugiero que sobre la imagen "botón derecho/ guardar imagen como.../" guárdala como un documento de imagen tuyo, y luego ábrela con tu "visor de imágenes" y haz zoom. También puedes descargar,la original, con más calidad aquí.




Os animo a transmitirme comentarios y sugerencias.
Un saludo para todos.

(CONTINÚA)







31 enero 2012

COMO ENCENDER UN DIODO LED.

PARA REPASAR: Ley de Ohm. Conceptos básicos de un diodo.


No hace demasiado tiempo he editado una entrada de electrónica para niños y como hacer un educativo juguete. Por sencillez he usado, en aquel montaje, una bombilla. Ahora se me ha ocurrido, que usando un led consumiría menos, y es una buena forma de aprender a polarizar un diodo led. Sustituiremos pues, la bombilla por un diodo led y una resistencia para limitar la corriente que pasa por este led y no quemarlo.

La pila que usaré seguirá siendo la de 4.5V. El led uno corriente cualquiera. Y tenemos que calcular la resistencia.
Somos conscientes de que el diodo solo permite que la corriente circule, y por lo tanto alumbre, en  una posición. Para colocarlo correctamente con este propósito, el led debe estar polarizado directamente. El positivo de la pila asociado al ánodo   y el negativo al cátodo.


Una primera aproximación de como funciona un diodo sería pensar en un interruptor. Si colocamos el diodo en un sentido pasa la corriente (circuito cerrado) y si lo colocamos en el contrario no pasa (circuito abierto). Pero para este caso tendremos que pensar en  una segunda aproximación. Tendremos en cuenta que el diodo al conducir en polarización directa (haciendo de interruptor cerrado y alumbrando) tiene una caída de tensión más o menos fija. Si fuese un diodo de silicio corriente esta "barrera de potencial" a partir de la cual el diodo funciona como interruptor cerrado es de 0.7V. En uno de germanio sería aproximadamente de 0.3V. Pero el caso de los diodos led tendremos en cuenta lo siguiente: la barrera de potencial varía según el dopado del cristal que se use para conseguir diferentes colores. Desde 1v más o menos para diodos de infrarrojos, 1.5v para rojos, 1.6v para amarillos, 2.7 para verdes, y hasta unos 3v en diodos azules.
El diodo que  he encontrado usado por el taller es verde. Suponemos pues, una barrera de potencial a superar de 2.7V. Y la intensidad que circulará será entre 10 y 40mA. Vamos a hacer los cálculos pensando en 15mA. Si es suficiente para que alumbre, mejor que no consuma demasiada corriente. Así aumentaremos la duración de la batería.

La intensidad que pasará por el diodo es igual que la que pase por la resistencia, puesto que están en serie. La caída de tensión en la resistencia será, la de la pila, menos, la que caiga en el diodo (hemos quedado en trabajar con una aproximación de 2.7v).
Vrersistencia = Vpila - Vled = 4.5 - 2.7 =1.8v
R= Vresistencia / Iresistencia = 1.8 / 0.015 = 120ohmios

Y la potencia que tendrá que disipar la resistencia también se deriva de la ley de Ohm: W=V*I
PotenciaResistencia (W)=Vresistencia * Iresistencia = 1.8 * 0.015 = 0.027 w

Una resistencia pequeña, que disipe hasta de 1/4 de watio (0.250w), nos sobra con margen suficiente.

Veremos que encontramos por el taller:
La resistencia de 120 ohmios.
Un diodo led verde usado al que le sueldo unos cablecitos.
Y la pila de petaca de 4,5

Montamos y medimos a ver si la teoría se parece a la práctica. Tensión del diodo la supusimos de 2.7v y da 2.5v. La intensidad supusimos 15mA y da 16.5mA. Todo funciona y nada se calienta. Probamos con una fuente y conseguimos que el diodo alumbre hasta unos 2 voltios de alimentación. Creo que cumple las espectativas y no hemos quemado nada.


Perfecto para usar con nuestro juguete descrito en otra entrada anterior: Así aumentaremos la duración de la pila respecto a la bombilla.



22 enero 2012

ELECTRÓNICA PARA NIÑOS O PRINCIPIANTES: Juguete que señala la respuesta correcta

PARA REPASAR: Esto se trata de una primera aproximación a la electricidad. No creo que se necesite repasar. Si acaso la estructura elemental del átomo.


Esto es un sencillo juguete, con el que yo recuerdo haberme divertido de pequeño. Recuerdo que tenía un mapa, y con él aprendí las ciudades de mi país. Recuerdo también descubrir como funcionaba con un libro que ahora debe de ser casi imposible conseguir: "Electrónica recreativa",de Gabriel Reuben. De donde partió la idea original y me animó con diez años a destripar mi mapa y discurrir mi versión.



Como lo haremos con una pila, no entraña riesgo alguno y es ideal para que un niño o principiante entienda como funciona un circuito eléctrico elemental, la diferencia entre circuito cerrado y abierto, y materiales aislantes y conductores. 
El esquema del conexionado no tiene complicación. Se trata de encender una bombilla con una pila.



La electricidad consiste en el desplazamiento de los electrones de unos átomos a otros.
Hay materiales, como los metales, que por su estructura atómica, tienen algunos de sus electrones medio sueltos y se mueven fácilmente. Se dice que son "materiales buenos conductores de la electricidad". Otros, tienen todos sus electrones bien sujetos a cada átomo y es difícil conseguir que se muevan de unos átomos a otros. Éstos son "materiales malos conductores de la electricidad".
La pila es un generador de corriente eléctrica. Por medio de reacciones químicas consigue una "tensión" o "diferencia de potencial eléctrico" (voltaje). Algo similar a cuando levantas un peso del suelo o tensas una goma. Esta "tensión" es capaz de repeler electrones (que tienen carga negativa) con el polo negativo y atraerlos por el positivo. También se trata de algo similar a lo que ocurre con los polos norte y sur de un imán. Polos iguales se repelen y distintos se atraen.
Moverse por el filamento de la bombilla, a los electrones les "cuesta" más, y como si rozasen, calientan a éste hasta dar luz. No se quema, porque el interior de la bombilla está vacío de aire y oxigeno, y sin oxigeno las cosas no arden.
Sólo necesitamos, con un cable conductor (de cobre por ejemplo), unir los polos de la pila intercalando la bombilla en el medio.
El "circuito está cerrado". Los electrones salen y regresan a la pila. Y la bombilla alumbra.
Si cortamos el conductor, el "circuito está abierto". Los electrones no pueden "circular" y la bombilla estará apagada.Esto es lo que hace un interruptor para apagar la luz: "abrir el circuito".


Por el momento, vamos a montar este circuito. Necesitaremos pila, bombilla, portalámparas y cable. Yo usaré una pila de petaca de 4,5v porque me parece cómoda para conectar los cables. Es fácil enroscarlos con los dedos sobre los bornes, si trabajamos con cables de varios hilillos. La bombilla debería ser del mismo voltaje que la pila o un poco más. Si es de menos alumbrará demasiado y corremos es riesgo de que se queme. Si es de un poco más alumbrará menos, pero no le pasará nada. Te puedes encontrar con diferentes tipos de portalámparas. No hay mayor problema siempre que tengas claro cuales son los dos terminales de una bombilla, y como se conectan éstos en el portalámparas. Uno de los terminales del filamento siempre está conectado a la rosca de la bombilla. Y el otro terminal , a la gotita de plomo o estaño que tiene en el culo. Si miramos el portalámparas por el interior podremos deducir en donde se conecta la rosca y en donde el culo. En el modelo de portalámparas que yo usaré hay que tener cuidado de que el cable que va al tornillo no toque a las aletas metálicas que se unen a la rosca.


Colocar el cable en el tornillo y que no se suelte cuando se aprieta la rosca puede tener su dificultad si no se es hábil manualmente.

Comento un truco:

Pelar el extremo del cable con bastante exceso.
Dividir el grupo de cablecitos en dos partes más o menos iguales.
Trenzar cada parte por separado.
Con estas dos trenzas empezamos a trenzarlas a su vez, envolviendo el tornillo.
Nos quedará el agujero, a modo de arandela de conexión.
Solo debemos cortar el hilo sobrante.
Y apretar la tuerca.


El conectar los demás extremos no tiene mayor dificultad, ni es crítico como este tornillo central. Un cable flojo o mal conectado puede tocar en el resto del chasis y cortocircuitar los extremos de la bombilla. Aquí, trabajando con una pila, no pasará nada más grave que descargar la pila. Pero con tensión elevada, como la de la red eléctrica, podría ser más peligroso y quemar la instalación o hacer saltar los fusibles o protecciones.

Finalmente conseguimos tener la bombilla alumbrando.
Ahora si cortamos el cable y abrimos el circuito la bombilla dejará de alumbrar. Si unimos los extremos del cable cortado con un material aislante como una hoja de cartulina, o cinta aislante, la bombilla seguirá apagada. Pero si usamos un material conductor de la corriente, como el papel de aluminio, la bombilla alumbrará.


Hasta aquí, el aprendizaje. Ahora viene lo divertido:

Yo haré el juego imprimiendo un mapa con los cinco continentes con mi impresora en una cartulina, pero cada persona puede tener múltiples ideas o intereses.
Además del mapa, en los extremos escribiré el nombre de cada continente. Haré un agujero junto al nombre y otro en el continente en cuestión. Si uno un agujero de nombre correcto con un agujero de mapa correcto, usando papel de aluminio, que es conductor; cuando una estos agujeros con los cables cerraré el circuito y la bombilla alumbrará indicando que la asociación es correcta. Si uno dos agujeros que no están asociados con papel de aluminio, el circuito permanecerá abierto y la bombilla no alumbrará indicando un error. La idea es simple pero podemos llegar a hacer un juego bastante complicado. Por el revés de la cartulina, tendremos que tener en cuenta, que las diferentes tiras de papel de aluminio no deben tocarse para que no se "mezclen" los diferentes circuitos. Esto lo evitaremos con cinta aislante sobre el cruce de papeles que no queremos que se toquen. La parte trasera la cubrimos con más cartulina y ya tenemos un "cartón de juego", práctico, educativo y divertido.


Para alguien un pelín más avanzado puede ser interesante usar un diodo en vez de la bombilla.


28 septiembre 2011

COMO HACER UN DESOLDADOR CASERO CON UN COMPRESOR DE AIRE BARATO

Para repasar: Compresor de pistón.

 
Esta vez se trata de ahorrarse algo de dinero. Si no puedes permitirte el lujo de comprarte un buen desoldador, como era mi caso hace unos años, aquí te propongo un apaño mucho más útil que las bombas de succión o las peras de goma.y casi tan eficaz como uno profesional. Sólo le faltaría la regulación de temperatura.

 La idea surgió al encontrar, tiradísimo de precio en un supermercado, uno de esos compresores para inflar una colchoneta que se enchufan al mechero del coche.

 Y la idea es sencilla. Un compresor para inflar suelta el aire por un extremo pero necesita "absorberlo" por otro. Si  encontramos el orificio por donde entra el aire, tendremos el punto por el que "chupar" el estaño. Únicamente tendremos que unirlo a una punta desoldadora y añadir algún tipo de filtros para que el estaño no llegue al compresor.


Este compresor es de pistón. Funciona de forma similar al émbolo de una jeringuilla. Cuando tiramos absorbe el aire, y cuando empujamos lo hecha. Si tenemos un par de orificios y cada uno de ellos dispone de una válvula que tapone el aire en sentidos inversos tendremos un orificio por el que entra el aire y otro por el que sale. Algún mecanismo (como un motor eléctrico en nuestro caso) moverá el émbolo (en nuestro compresor un cigüeñal, biela y cilindro similar al motor de un coche).


  

En mi caso destripo un poco el compresor para buscar los orificios de entrada A y salida B del aire.


Por el orificio A entra el aire. Por el tubo B sale el aire hacia la goma de salida. Ahora el trabajo consiste en poner una goma al orificio A por la que "chupar" el aire.


 Se puede observar el cilindro desmontado. Se observa el pistón que actúa dentro del cilindro. Las válvulas de entrada y salida del aire son unas gomitas colocadas en dos orificios en la tapa del cilindro.


 La gomita A está por dentro del cilindro sujeta con una chapita. Baja cuando entra el aire. La gomita B está por fuera del cilindro. Sube cuando sale el aire.




El primer problema me lo encontré con el poco espacio para colocar una goma sobre el orificio de entrada de aire (A). Se trata de un agujero demasiado pequeño. Mi opción fue la aguja de una jeringilla para pinchar caballos. La parte metálica la corté. Se trata de que introduzca por el orificio pero no obstruya el "sube y baja" de la válvula de admisión.

Pegué con pegamento rápido. La cánula de plástico que uniría la aguja a la jeringuilla, que se observa bien en la foto, me servirá para sujetar un tubo algo más grueso con silicona, al que unir la goma de entrada de aire.



Ya tengo el compresor adaptado para conectar la "absorción" de aire. Usaré un tubo de latón de 4mm de diámetro para las uniones que conseguí en una ferretería. Gomas. La azul me la regalaron en una tienda de repuestos de coches. Buscaba algo resistente que aguantase algo de calor. La transparente se usa en los presostatos de las lavadoras. A mi desoldador de pera le saco la pera de goma.

Se trata ahora de unir la punta desoldadora con la entrada de aire del compresor. Pero aquí tenemos otro problema. El estaño que absorbamos no puede llegar a las válvulas del compresor porque las estropearía. Es necesario hacer unos filtros.


Lo he solucionado con las cajitas de unos carretes de fotografía, al que he hecho dos orificios en los extremos y he introducido unas conexiones de tubo flexible pegado con silicona. El filtro que habrá que cambiar cada cierto tiempo será con un trozo de esponja. He puesto dos filtros. Uno cerca de la punta desoldadora y otro cerca del compresor (el que tengo transparente para poder ver si se acumula el peligroso estaño).

Aquí se puede ver la parte mecánica. Ahora solo nos queda poner una fuente de alimentación y pulsador a modo de interruptor para accionar el compresor. Me he encontrado con que el consumo de corriente es demasiado alto para mi fuente de alimentación de laboratorio (un poco más de 3 A) así que he montado todo con un transformador más puente rectificador que tenía de desguace tirado por el desván. Ya ves que el filtraje y la calidad de la tensión no es importante, siempre que sean los 12v en continua, que muestra en las características el compresor que originalmente era para el mechero de un coche. Que el filtrado y estabilizado de la tensión sea deficiente no tiene importancia.



El esquema eléctrico, creo que no tiene complicación. Un pulsador dispuesto en el mango del desoldador dará paso a la corriente hacia el compresor. OBSERVA QUE TRABAJAMOS SÓLO CON 12 V EN CONTINUA, COMO LA BATERÍA DE UN COCHE. NO SE TE OCURRA PONER UN PULSADOR CON MÁS TENSIÓN (220V O 115V) EN LA PUNTA DEL DEDO.


El resultado es el esperado. El compresor "anda" un poco por la mesa y es algo ruidoso, pero cumple su función perfectamente. Está claro que aquí propongo chapuzas. El sujetar todo un poco mejor y hacerlo más bonito está en tus manos, pero la operatividad es buena.
Os dejo una prueba en video.  (Este enlace es al primer sitio en donde he colgado el video: TuTV. Por publicidad excesiba, continuos fallos, e inoperabilidad, en el cuadro de video que sigue he optado por youtube a fecha Sept2016. Conservo, de alguna manera, los dos enlaces, para aumentar las posibilidades de visionado)





Como siempre espero que esto le pueda servir a alguien y acepto comentarios... Un saludo.


24 junio 2011

Como hacer funcionar un display spi VFD (Vacuum Fluorescent Display) Pinguino (o arduino)+16LF01UA3






PARA REPASAR: Datasheet del display 16LF01UA3 (lo he consiguido en pdf buscando en la web por "16lf01ua3 untitle"); Pinguino Pic (lo mismo que arduino pero con microcontrolador de Microchip del que he comentado en una entrada anterior, software libre y hardware libre fácil de construir, que puedes ver si buscas en la web "pinguino pic hackinglab", fíjate expecialmente en el tutorial; conocimientos básicos de programación en C, tener un Manual de progamción Arduino que puedes también descargar en pdf desde la red para conocer que ordenes de c se pueden usar con arduino.



Esta vez se trata de hacer funcionar un display alfanumerico VFD (Display Fluorescente de Vacio). He conseguido alguno de despieces, y he encontrado documentación de éste en internet (16LF01UA3). Mi idea original es tratar de imitar un luminoso publicitario que pase continuamente un mensaje de derecha a izquierda.
Con una ojeada a la hoja de características del display Samsumg 16LF01UA3 nos hacemos con los pines y una idea de su funcionamiento.

Pin1 y pin2: Vcc(+5v).
Pin3,4,5,6,7: No conectados. El 3 falta como "llave" que impida conectar al revés.
Pin8: SCLK Activa por flanco de bajada el bit que señale DATA.
Pin9: DATA El bit (0 ó 1) se va añadiendo a un registro cada vez que SCLK baja de 1 a 0 hasta que forma un byte (8 bits) como código de control del display.
Pin10: /RST A nivel bajo activa el reset de todo el display.
Pin11 y pin12: GND


Así que tendremos que alimentar con 5 voltios al display (pines1-2, 11-12), y el "Pinguino" (placa similar a Arduino) que usaremos para manejar los tres pines: SCLK, DATA, y RESET.

Monto todo sobre una protoboard. En la programación del Pinguino "definiremos" como salidas: la 7 para el SCLK, la 6 para el RESET, y la 5 para el DATA.






Como mi experiencia con el pinguino es mínima, y aquí se trata de aprender, no me preocuparé de librerias previas, ni aprovecharé lo que hayan hecho otros. Programaremos "como los hombres", a pelo, usando las ordenes más elementales y genéricas para ir montando nuestras funciones... Creo que he descrito ampliamente con notas en el código pero aclararé como he ido planteando el asunto.
El display se maneja, basicamente, "emitiendo" secuencias de bits, que en grupos de 8 forman "palabras" que el display va entendiendo de determinada manera. Los códigos vienen en la hoja de características del display. El display alamacenará un bit cuando la señal SCLK pase de nivel alto (5v) a bajo (0v) y ese bit será el que en ese momento tenga el pin DATA. La señal /RESET deberá permanecer a nivel alto. A nivel bajo reseteará todo y tendremos que volver a empezar.
Lo primero ha sido la funcion sclkfall() que hace que la señal de SCLK pase a nivel bajo y por tanto el display "acepte" lo que hay en DATA. Y luego, usando ésta defino l() para meter un uno (5v), y o() para "meter" un cero (0v). OJO: l() parece un uno pero es una "L"minúscula, y o() parece un cero pero es una "O"minúscula. Uso el parecido porque no puedo hacer una función que empiece por un número y de esta forma , a posteriori es muy cómodo, porque es fácil ver el byte que queiro enviar en cada momento. Luego todo es enviar bytes. ¿Cúal?, se sabe mirando la hoja de características, aunque voy explicando en el código.


// Probando display vfd 16LF01UA3

// Usaremos un pinguino con pic18f2550
// Anadir la linea siguiente si es con pic18f4550
// #define PIC18F4550


#define SCLK 7 //manejaremos SCLK por pin7
#define RST 6 // /RST por pin6
#define DATA 5 // DATA por pin5

int colocarPuntero(int En);//Prototipado porque pasa valor
////////////////////////////////////////////////////////////
// TEXTO PARA EL DISPLAY en modo scroll AQUI
char Mensaje[100]="Jueves, 16 de junio ";// 3" "al final
int posicionUltLetra=22;
// TAMAÑO ARRAY Mensaje[x] DEBE SER MAYOR QUE EL NUMERO DE CARACTERES
// posicionUltLetra INDICARA EL NUMERO DE CARACTERES.
////////////////////////////////////////////////////////////
int scroll=1;// 1=>Desplazamiento continuo del texto izq-der
// 0=>No se controla el desplazamiento.
// 2=>Prueba (poniendo codigo en su sitio) cosas nuevas
////////////////////////////////////////////////////////////

char digDisplay[17]=" ";// 17 espacios
//Representa los caracteres en cada
// posicion del display, usaremos [1...16]
// uno por cada digito. El [0] no lo usamos
int posicionMensaje,i;
//No.1er.caracter escribir en display
// i contador que no puedo definir en loop()


/////////////////////////////////////////////
void setup()
{
pinMode(SCLK,OUTPUT); //Todas seran salidas hacia
pinMode(RST,OUTPUT); //el display
pinMode(DATA,OUTPUT);

resetdisplay(); // La primera vez reseteamos display
numdigit(); // configuramos el numero de digitos
brillo(); // la intensidad de los digitos
BorrarDisplay(); // Borrar
posicionMensaje=0;//Por donde empezaremos a leer el Mensaje[]
}

void loop()
{

if(scroll==1)
{
// Guardamos en cada digDisplay[i] el caracter que le toca a ese digito
// Pretendemos que el texto corra de derecha a izquierda continuamente
for(i=1;i<16;i++)
{
digDisplay[i]=digDisplay[i+1];
//Cada digito corre de derecha a izquierda
}
digDisplay[16]=Mensaje[posicionMensaje];
//El ultimo digito de la derecha es el nuevo que leemos de Mensaje[]

if (posicionMensaje==posicionUltLetra)
// Si era el ultimo caracter hay que volver a leer por el principio
{
posicionMensaje=0;
}
else
// Si todavia no llegamos preparamos para leer el siguiente
{
posicionMensaje=posicionMensaje+1;
//La siguiente vez leeremos el caracter siguiente de Mensaje[]
}



// Representamos cada caracter en su digDisplay
for(i=1;i<17;i++)
{
colocarPuntero(i);
switch(digDisplay[i])
{
case '@':Arroba();break;
case 'A':case 'a':A();break;
case 'B':case 'b':B();break;
case 'C':case 'c':C();break;
case 'D':case 'd':D();break;
case 'E':case 'e':E();break;
case 'F':case 'f':F();break;
case 'G':case 'g':G();break;
case 'H':case 'h':H();break;
case 'I':case 'i':I();break;
case 'J':case 'j':J();break;
case 'K':case 'k':K();break;
case 'L':case 'l':L();break;
case 'M':case 'm':M();break;
case 'N':case 'n':N();break;
case 'O':case 'o':O();break;
case 'P':case 'p':P();break;
case 'Q':case 'q':Q();break;
case 'R':case 'r':R();break;
case 'S':case 's':S();break;
case 'T':case 't':T();break;
case 'U':case 'u':U();break;
case 'V':case 'v':V();break;
case 'W':case 'w':W();break;
case 'X':case 'x':X();break;
case 'Y':case 'y':Y();break;
case 'Z':case 'z':Z();break;
case '(':AbreParentesis();break;
case '\\':BarraIzqDer();break;
case '/':BarraDerIzq();break;
case ')':CierraParentesis();break;
case '_':GuionBajo();break;
case '\"':Comillas();break;
case '#':Almohadilla();break;
case '$':Dolar();break;
case '%':Porcentaje();break;
case '&':Andpersand();break;
case '\'':Apostrofe();break;
case '<':MenorQue();break;
case '>':MayorQue();break;
case '*':Asterisco();break;
case '+':Mas();break;
case ',':case ';':Espacio();PuntoyComa();break;// El ; y el .
case '.':Espacio();Punto();break;//se asocian al ultimo
case '0':Cero();break; //caracter. No hay coma pero queda
case '1':Uno();break; //parecido el punto y coma.
case '2':Dos();break;
case '3':Tres();break;
case '4':Cuatro();break;
case '5':Cinco();break;
case '6':Seis();break;
case '7':Siete();break;
case '8':Ocho();break;
case '9':Nueve();break;
case '?':Interrogacion();break;
case '=':Igual();break;
case ' ':Espacio();break;
default:Espacio();
}
}
delay(400); //Retraso para poder visualizar
BorrarDisplay();
}


if (scroll==0)
{
// Poniendo al principio la constante scroll a 0
// cada letra (llamada a su funcion) ira despues
// de la anterior y al acabar empezara linea nueva.
BorrarDisplay();
H();O();L();A();Espacio();
M();U();N();D();O();Punto();Espacio();
delay(1000);BorrarDisplay();
Q();U();E();Espacio();
T();A();L();Espacio();
E();S();T();A();M();O();S();Interrogacion();
delay(1500);
}
if (scroll==2)
{
// Poniendo la constante scroll a 2 aquí puedes
// hacer pruebas si arriesgar demasiado...
}
}//////////////////////////////////////////////////////////


// Funciones para controlar el display
// Ver datasheet 16lf01ua3.
void sclkfall() // SCLK activa por flanco
{ // de bajada lo que marque DATA
digitalWrite(SCLK,HIGH);
digitalWrite(SCLK,LOW); // y preparando la siguiente bajada
digitalWrite(SCLK,HIGH);// vuelve a quedar a nivel alto
}


void o() // La funcion o() ("o" minuscula) marca un 0
{
digitalWrite(DATA,LOW);
sclkfall();
}
void l() // La funcion l() ("L" minuscula) marca un 1
{
digitalWrite(DATA,HIGH);
sclkfall();
}



void resetdisplay() // resetea el display
{ // activando a nivel bajo RST mas
digitalWrite(RST,LOW); // de 1ms y volvieno a nivel alto
delay(2); // para funcionamiento normal
digitalWrite(RST,HIGH);
delay(2);
}


void numdigit() // Define cuantos digitos usaremos
{ // los 16 en este caso "11000000"
l();l();o();o();o();o();o();o();
}


void brillo() // Para configurar la intensidad del display
{ // Maxima 11111111
l();l();l();l();l();l();l();l();
}


int colocarPuntero(int En)// Elege el digito que se va a escribir
{
l();o();l();o();// Primer cuarteto ordena control de puntero 1010

switch(En) // Segundo cuarteto indica dígito. De izq. a der.
{ // El primero 1111 y siguientes 0000,0001,...1110
case 1:l();l();l();l();break;
case 2:o();o();o();o();break;
case 3:o();o();o();l();break;
case 4:o();o();l();o();break;
case 5:o();o();l();l();break;
case 6:o();l();o();o();break;
case 7:o();l();o();l();break;
case 8:o();l();l();o();break;
case 9:o();l();l();l();break;
case 10:l();o();o();o();break;
case 11:l();o();o();l();break;
case 12:l();o();l();o();break;
case 13:l();o();l();l();break;
case 14:l();l();o();o();break;
case 15:l();l();o();l();break;
case 16:l();l();l();o();break;
default:l();l();l();l();
}
return(0);
}


void BorrarDisplay() // Borra escribiendo 16 espacios
{
int c;
colocarPuntero(1);
for (c=1;c<17;c=c+1)
{
Espacio();
}
}

void Retraso()
{
delay(0); // Ajustar restraso para poder leer
}



////////// Definiciones de letras //////////////

void Arroba() // Codigo para escribir @ 00000000
{o();o();o();o();o();o();o();o();Retraso();}
void A() // Codigo para escribir A 00000001
{o();o();o();o();o();o();o();l();Retraso();}
void B() // Codigo para B 00000010
{o();o();o();o();o();o();l();o();Retraso();}
void C() // Codigo para C 00000011
{o();o();o();o();o();o();l();l();Retraso();}
void D() // Codigo para escribir D 00000100
{o();o();o();o();o();l();o();o();Retraso();}
void E() // Codigo para escribir E 00000101
{o();o();o();o();o();l();o();l();Retraso();}
void F() // Codigo para escribir F 00000110
{o();o();o();o();o();l();l();o();Retraso();}
void G() // Codigo para escribir G 00000111
{o();o();o();o();o();l();l();l();Retraso();}
void H() // Codigo para escribir H 00001000
{o();o();o();o();l();o();o();o();Retraso();}
void I() // Codigo para escribir I 00001001
{o();o();o();o();l();o();o();l();Retraso();}
void J() // Codigo para escribir J 00001010
{o();o();o();o();l();o();l();o();Retraso();}
void K() // Codigo para escribir K 00001011
{o();o();o();o();l();o();l();l();Retraso();}
void L() // Codigo para escribir L 00001100
{o();o();o();o();l();l();o();o();Retraso();}
void M() // Codigo para escribir M 00001101
{o();o();o();o();l();l();o();l();Retraso();}
void N() // Codigo para escribir N 00001110
{o();o();o();o();l();l();l();o();Retraso();}
void O() // Codigo para escribir O 00001111
{o();o();o();o();l();l();l();l();Retraso();}
void P() // Codigo para escribir P 00010000
{o();o();o();l();o();o();o();o();Retraso();}
void Q() // Codigo para escribir Q 00010001
{o();o();o();l();o();o();o();l();Retraso();}
void R() // Codigo para escribir R 00010010
{o();o();o();l();o();o();l();o();Retraso();}
void S() // Codigo para escribir S 00010011
{o();o();o();l();o();o();l();l();Retraso();}
void T() // Codigo para escribir T 00010100
{o();o();o();l();o();l();o();o();Retraso();}
void U() // Codigo para escribir U 00010101
{o();o();o();l();o();l();o();l();Retraso();}
void V() // Codigo para escribir V 00010110
{o();o();o();l();o();l();l();o();Retraso();}
void W() // Codigo para escribir W 00010111
{o();o();o();l();o();l();l();l();Retraso();}
void X() // Codigo para escribir X 00011000
{o();o();o();l();l();o();o();o();Retraso();}
void Y() // Codigo para escribir Y 00011001
{o();o();o();l();l();o();o();l();Retraso();}
void Z() // Codigo para escribir Z 00011010
{o();o();o();l();l();o();l();o();Retraso();}
void AbreParentesis() // Codigo para escribir ( 00011011
{o();o();o();l();l();o();l();l();Retraso();}
void BarraIzqDer() // Codigo para escribir \ 00011100
{o();o();o();l();l();l();o();o();Retraso();}
void BarraDerIzq() // Codigo para escribir / 00101111
{o();o();l();o();l();l();l();l();Retraso();}
void CierraParentesis() // Codigo para escribir ) 00011101
{o();o();o();l();l();l();o();l();Retraso();}
void GuionBajo() // Codigo para escribir _ 00011111
{o();o();o();l();l();l();l();l();Retraso();}
void Comillas() // Codigo para escribir " 00100010
{o();o();l();o();o();o();l();o();Retraso();}
void Almohadilla() // Codigo para escribir # 00100011
{o();o();l();o();o();o();l();l();Retraso();}
void Dolar() // Codigo para escirbir $ 00100100
{o();o();l();o();o();l();o();o();Retraso();}
void Porcentaje() // Codigo para escribir % 00100101
{o();o();l();o();o();l();o();l();Retraso();}
void Andpersand() // Codigo para escribir & 00100110
{o();o();l();o();o();l();l();o();Retraso();}
void Apostrofe() // Codigo para escribir ' 00100111
{o();o();l();o();o();l();l();l();Retraso();}
void MenorQue() // Codigo para escribir < 00101000
{o();o();l();o();l();o();o();o();Retraso();}
void MayorQue() // Codigo para escribir > 00101001
{o();o();l();o();l();o();o();l();Retraso();}
void Asterisco() // Codigo para escribir * 00101010
{o();o();l();o();l();o();l();o();Retraso();}
void Mas() // Codigo para escribir + 00101011
{o();o();l();o();l();o();l();l();Retraso();}
void PuntoyComa() // Codigo para escribir ; 00101100
{o();o();l();o();l();l();o();o();Retraso();}
void Menos() // Codigo para escribir - 00101101
{o();o();l();o();l();l();o();l();Retraso();}
void Punto() // Codigo para escribir . 00101110
{o();o();l();o();l();l();l();o();Retraso();}
void Cero() // Codigo para escribir 0 00110000
{o();o();l();l();o();o();o();o();Retraso();}
void Uno() // Codigo para escribir 1 00110001
{o();o();l();l();o();o();o();l();Retraso();}
void Dos() // Codigo para escribir 2 00110010
{o();o();l();l();o();o();l();o();Retraso();}
void Tres() // Codigo para escribir 3 00110011
{o();o();l();l();o();o();l();l();Retraso();}
void Cuatro() // Codigo para escribir 4 00110100
{o();o();l();l();o();l();o();o();Retraso();}
void Cinco() // Codigo para escribir 5 00110101
{o();o();l();l();o();l();o();l();Retraso();}
void Seis() // Codigo para escribir 6 00110110
{o();o();l();l();o();l();l();o();Retraso();}
void Siete() // Codigo para escribir 7 00110111
{o();o();l();l();o();l();l();l();Retraso();}
void Ocho() // Codigo para escribir 8 00111000
{o();o();l();l();l();o();o();o();Retraso();}
void Nueve() // Codigo para escribir 9 00111001
{o();o();l();l();l();o();o();l();Retraso();}
void Interrogacion() // Codigo para escribir ? 00111111
{o();o();l();l();l();l();l();l();Retraso();}
void Igual() // Codigo para escribir = 00111101
{o();o();l();l();l();l();o();l();Retraso();}
void Espacio() // Codigo para el espacio 00100000
{o();o();l();o();o();o();o();o();}

/////////////////////////////////////Sancos 16-6-2011
////////////////////////////////////

El código sale aquí un poco enmarañado porque si copio y pego pierdo los tabulados. Pero para seguir un poco las explicaciones sirve.
Si quieres acceder al "archivo.pde" que puede leer directamente el IDE del pinguino, puedes descargarlo desde aquí.
Actualmente yo estoy usando la versión "Pinguino beta 9.04" y es con la que he probado todo esto.
También me ha parecido útil el que puedas descargar el programa como "documento.doc" para que sea más legible con colores y sangrados. Pero recuerda que esto no correrá en el editor del Pinguino. Tendrías que pasarlo escribiendo a pelo.

También añado aquí (a Diciembre del 2014) si quieres descargar una versión revisada para arduino ("archivo.ino"). Probado con arduino uno y el ide 1.0.4 a raiz de un comentario anónimo del  6 de diciembre de 2014 (léelo para observaciones) advirtiendo de que el código para pinguino no compilaba en arduino.

Al final he usado un if para, según el valor de la constante scroll, escoger un código que hace pasar de derecha a izquierda lo que pongamos en Mensaje[x] (video que pone una fecha); o no controlar la posición de cada letra y que sea el display el que automaticamente ponga una tras otra (video "Hola mundo, como estamos?"); o en una tercera opción, podemos hacer pruebas sin estropear lo que sabemos que funciona. En esta última parte no he puesto código.

Supongo que se entiende facilmente que las funciones l(), y o() envían, respectivamente, un 1 y un 0 al display.

Para cada letra se llama a su función correspondiente. Esta envía ceros y unos con el código correcto, según la hoja de características. Observa que el código que corresponde a escribir una letra tiene como bit más significativos (los primeros que se emiten) dos ceros, y los seis restantes indican la letra. Los que no empiecen por dos ceros son códigos de control: el brillo (yo sólo uso el maximo- brillo() -),número de dígitos (yo uso los 16- numdigit() -),la posición del siguiente caracter (aquí la función no es tan simple porque para conseguir que parezca que se desplacen tengo que posicionar cada letra- colocarPuntero() -y uso todos los códigos).
Algunas funciones especiales son: resetdisplay() en la que activo la linea de reset, o BorrarDisplay() que escribe 16 espacios. La función retraso() ,que aquí parecerá inútil, permite hacer pruebas con diferentes velocidades. Si escribes todo sin perder tiempo no verás nada.

Si al principio del código pones scroll=0 el asunto solo se tratará de ir "llamando a letras" estas irán apareciendo en la posición 1, luego 2, luego 3,...luego 16, luego 1, luego 2... Esto lo hace automaticamente el display 16LF01UA3. Al poner una letra suma la siguiente posición un paso, excepto para la coma y el punto.

Si el scroll=1, se complica un poco la cosa. Porque intento que el texto (el que quieras poner en Mensaje[x]) se desplace continuamente como en un luminoso publicitario. Mensaje[x] es un array. Necesitas que el texto quepa dentro, así que x debe de ser al menos el número de caracteres que quieras representar. El primer carácter será Mensaje[0] y el último Mensaje[x-1]. Observese que Mensaje[x] debería ser un carácter especial que marque el final de la cadena. He tenido problemas con esto. Así que en vez de "calcular" el final de la cadena, he optado por utilizar una constante posicionUltLetra que me marca cual es la última letra.
Luego el truco será en usar la cadena puente digDisplay[17] que se corresponderá a cada caracter real del display (1...16). Será 17, porque la posición 0 y 17 no se usan. Al principio esta cadena tiene espacios. Luego iremos pasando cada letra un puesto a la izquierda. ¿Y que pasa con la última? Pues que será la nueva, que vamos controlando con posicionMensaje teniendo en cuenta que después del final, vendrá el principio.
Una vez que tenemos la cadena digDisplay[17] llena de forma apropiada, escribimos cada elemento en su posición, llamando a las función más apropiada.
Y repetimos...



Espero no haberme liado mucho.
Me gustaría que hicieseis comentarios, aunque no sean demasiado buenos. Si son constructivos prenderé más. Y también me gustaría saber si alguien lo lee...


Bueno os dejo los videos.

Con desplazamiento, tipo luminoso publicitario:

Y sin desplacamiento:

POR FAVOR, valoraría comentarios... y siento la posible publicidad en mis enlaces pero es lo que tienen los alojamientos gratuitos...
Saludos.