USB interfaz

14
USB USB Universal Serial Bus es una interfaseplug&play entre la PC y ciertos dispositivos tales como teclados, mouses, scanner, impresoras, módems, placas de sonido, camaras,etc) . Una característica importante es que permite a los dispositivos trabajar a velocidades mayores, en promedio a unos 12 Mbps, esto es más o menos de 3 a 5 veces más rápido que un dispositivo de puerto paralelo y de 20 a 40 veces más rápido que un dispositivo de puerto serial. Como Funciona Trabaja como interfaz para transmisión de datos y distribución de energía, que ha sido introducida en el mercado de PC´s y periféricos para mejorar las lentas interfaces serie (RS-232) y paralelo. Esta interfaz de 4 hilos, 12 Mbps y "plug and play", distribuye 5V para alimentación, transmite datos y está siendo adoptada rápidamente por la industria informática . Es un bus basado en el paso de un testigo, semejante a otros buses como los de las redes locales en anillo con paso de testigo y las redes FDDI . El controlador USB distribuye testigos por el bus . El dispositivo cuya dirección coincide con la que porta el testigo responde aceptando o enviando datos al controlador . Este también gestiona la distribución de energía a los periféricos que lo requieran . Emplea una topología de estrellas apiladas que permite el funcionamiento simultáneo de 127 dispositivos a la vez . En la raíz o vértice de las capas, está el controlador anfitrión o host que controla todo el tráfico que circula por el bus . Esta topología permite a muchos dispositivos conectarse a un único bus lógico sin que los dispositivos que se encuentran más abajo en la pirámide sufran retardo . A diferencia de otras arquitecturas, USB no es un bus de almacenamiento y envío, de forma que no se produce retardo en el envío de un paquete de datos hacia capas inferiores . El sistema de bus serie universal USB consta de tres componentes: Controlador Hubs o Concentradores Periféricos USB soporta periféricos de baja y media velocidad . Empleando dos velocidades para la transmisión de datos de 1 . 5 y 12 Mbps se consigue una utilización más eficiente de sus recursos . Los periféricos de baja velocidad tales como teclados, ratones, joysticks, y otros periféricos para juegos, no requieren 12 Mbps . Empleando para ellos 1,5 Mbps, se puede dedicar más recursos del sistema a periféricos tales como monitores, impresoras, módems, scanner, equipos de audio . . . , que precisan de velocidades más altas para transmitir mayor volumen de datos o datos cuya dependencia temporal es más estricta . En las figuras 3 y 4 se puede ver cómo los hubs proporcionan conectividad a toda una serie de dispositivos periféricos

Transcript of USB interfaz

Page 1: USB interfaz

USB

USB Universal Serial Bus es una interfaseplug&play entre la PC y ciertos dispositivos tales como teclados, mouses, scanner, impresoras, módems, placas de sonido, camaras,etc) .

Una característica importante es que permite a los dispositivos trabajar a velocidades mayores, en promedio a unos 12 Mbps, esto es más o menos de 3 a 5 veces más rápido que un dispositivo de puerto paralelo y de 20 a 40 veces más rápido que un dispositivo de puerto serial.

Como Funciona

Trabaja como interfaz para transmisión de datos y distribución de energía, que ha sido introducida en el mercado de PC´s y periféricos para mejorar las lentas interfaces serie (RS-232) y paralelo. Esta interfaz de 4 hilos, 12 Mbps y "plug and play", distribuye 5V para alimentación, transmite datos y está siendo adoptada rápidamente por la industria informática .

Es un bus basado en el paso de un testigo, semejante a otros buses como los de las redes locales en anillo con paso de testigo y las redes FDDI . El controlador USB distribuye testigos por el bus . El dispositivo cuya dirección coincide con la que porta el testigo responde aceptando o enviando datos al controlador . Este también gestiona la distribución de energía a los periféricos que lo requieran .

Emplea una topología de estrellas apiladas que permite el funcionamiento simultáneo de 127 dispositivos a la vez . En la raíz o vértice de las capas, está el controlador anfitrión o host que controla todo el tráfico que circula por el bus . Esta topología permite a muchos dispositivos conectarse a un único bus lógico sin que los dispositivos que se encuentran más abajo en la pirámide sufran retardo . A diferencia de otras arquitecturas, USB no es un bus de almacenamiento y envío, de forma que no se produce retardo en el envío de un paquete de datos hacia capas inferiores .

El sistema de bus serie universal USB consta de tres componentes:

Controlador

Hubs o Concentradores

Periféricos

USB soporta periféricos de baja y media velocidad . Empleando dos velocidades para la transmisión de datos de 1 . 5 y 12 Mbps se consigue una utilización más eficiente de sus recursos . Los periféricos de baja velocidad tales como teclados, ratones, joysticks, y otros periféricos para juegos, no requieren 12 Mbps . Empleando para ellos 1,5 Mbps, se puede dedicar más recursos del sistema a periféricos tales como monitores, impresoras, módems, scanner, equipos de audio . . . , que precisan de velocidades más altas para transmitir mayor volumen de datos o datos cuya dependencia temporal es más estricta .

En las figuras 3 y 4 se puede ver cómo los hubs proporcionan conectividad a toda una serie de dispositivos periféricos

Page 2: USB interfaz

Diagrama de capas

En el diagrama de capas de la figura 5 podemos ver cómo fluye la información entre las diferentes capas a nivel real y a nivel lógico .

En dicha figura está materializada la conexión entre el controlador anfitrión o host y un dispositivo o periférico . Este está constituido por hardware al final de un cable USB y realiza alguna función útil para el usuario .

El software cliente se ejecuta en el host y corresponde a un dispositivo USB; se suministra con el sistema operativo o con el dispositivo USB . El software del sistema USB, es el que soporta USB en un determinado sistema operativo y se suministra con el sistema operativo independientemente de los dispositivos USB o del software cliente .

El controlador anfitrión USB está constituido por el hardware y el software que permite a los dispositivos USB ser conectados al anfitrión . Como se muestra en la figura 3, la conexión entre un host y un dispositivo requiere la interacción entre las capas . La capa de interfaz de bus USB proporciona la conexión física entre el host y el dispositivo . La capa de dispositivo USB es la que permite que el software del sistema USB realice operaciones genéricas USB con el dispositivo .

La capa de función proporciona capacidades adicionales al host vía una adecuada capa de software cliente. Las capas de función y dispositivos USB tienen cada una de ellas una visión de la comunicación lógica dentro de su nivel, aunque la comunicación entre ellas se hace realmente por la capa de interfaz de bus USB.

Page 3: USB interfaz

CIRCUITO INTERFACE USB A I2C S310425

USBI2C es un circuito interfaz que convierte señales usb en señales de bus I2C. El circuito se alimenta directamente desde el propio bus USB por lo que es muy cómodo de manejar. Este circuito utiliza el integrado convertidor de USB a Serie de la casa FTDI por lo que hay disponibles controladores tanto para Windows como para Apple y Linux. Una vez instalado el driver el circuito aparece en el ordenador como un puerto serie mas, por lo que todo lo que hace falta para poder controlar dispositivos I2C es mandar las ordenes directamente al puerto serie y el circuito se encarga de traspasarlas directamente al bus I2C. Gracias a este circuito se pueden controlar desde un PC cualquier dispositivo I2C, incluyendo los sensores de distancia por ultrasonido SRF02, SRF08, SRF10 de nuestro catalogo. Si no se utiliza el bus I2C, el circuito actúa como puertos de entrada y salida normales que se controlan desde el PC por USB. En este caso se tiene una línea de entrada y dos puertos mas que pueden funcionar como entradas o salidas. Hay disponible un software de control de ejemplo para Windows que permite controlar los puertos desde el PC.

El USB es una comunicación serie de alta velocidad. Ha sustituido en gran medida al famoso puerto serie RS-232, ello se debe en gran medida a que el USB utiliza señales digitales TTL, mientras que el puerto serie utiliza señales digitales entre -12 y +12 voltios, además de la gran diferencia de velocidad de transmisión entre ambos dispositivos.

La velocidad de transferencia a ido aumentando rápidamente a lo largo de estos años. Caben destacar 3 de estos:USB 1.0: baja velocidad (hasta 1.5Mbit/seg) usado en dispositivos de interfaz humana (HID) como ratones y teclados.USB 2.0: Alta Velocidad (hasta 480Mbit/seg) unos 60Mg/seg. (esta es la que usaremos) USB 3.0: Giga Velocidad, en fase experimental, (hasta 4.8Gbit/seg) unos 600 Mg/seg. Los buses son mucho más rápido debido a la incorporación de una fibra óptica al enlace de cobre.La transmisión del USB se realiza mediante un cable de cobre de par trenzado con una impedancía de unos 90 ohm llamados D+ y D-. Estos pueden dar energía a dispositivos externos, con una tensión de 5V y un máximo consumo de 500mA.Existen tres tipos de clases de dispositivos USB.Los HID(Human Interfaz Device) que vienen siendo teclados, ratones, pad´s para dibujo, joystics, etc.Los CDC (Comunication Divice Class) estos dispositivos son especificos para comunicación bidireccional, en mi caso lo eh utilizado esta clase para hacer un puerto serial virtual con el microcontrolador.Y los MSC (mass storage device class) esta clase es para el manejo almacenamiento de información, como memorias USB, discos duros externos, etc. Este modo no lo eh empleado.

Instrucciones Básicas del compilador que utilizaremos

Aquí una breve explicación de algunas instrucciones básicas que eh utilizado para el programa.

Variables:

Al igual que programar en C ó C++, tenemos declarar variables y para esto tenemos que definir que tipo de variable será, aqui algunos ejemplos:

Entonces para definir una variable de 8 Bits tendríamos que poner:

Page 4: USB interfaz

int8 Nombre_variable; (esta variable es desde 0 hasta 255)Si la variable es binaria:

int1 Nombre_variable; (esta variable es de 0 ó 1)

Si queremos asignarle un valor a estas variables, por ejemplo a la variable "dato" de tipo int8 le queremos guardar un numero 200 hacemos lo siguiente:

int8 dato;dato = 200;No hay mayor complicación con esto

DefinicionesLa instrucción #Define se puede utilizar para definir nombre predefinidos por nosotros para acceder al valor de todo un puerto del microcontrolador ó a pines por separado del mismo.

Ejemplo:El microcontrolador tiene el puerto A, Puerto B, Puerto C, Puerto D y Puerto E. Los pueden checar en el datasheet. Si queremos ponerle un nombre prefefinido por nosotros a los puertos E0, E1 para un fácil acceso a algo fisico, es decir quiero que el pueroto E0 se llame LED1 y que el puerto E1 se llame LED2 para no perderse tanto en el codigo mas adelante.Entonces hacemos lo siguiente:

#define LED1 PIN_E0#define LED2 PIN_E1

Ahora tambien podemos predefirnir nombres para instrucciones. Ejemplo. Las instrucciones Output_high y Output_low estan destinadas al manejo de pines del PIC, por ejemplo quiero encender el LED en el pin B0 y apagarlo enseguida:output_high(PIN_B0); output_low(PIN_B0);

Podriamos predefinir nombres para estas instrucciones lo cual lo hariamos asi;#define LED_ON output_high#define LED_OFF output_low

Una vez haciendo esto podriamos hacer lo mismo de prender y apagar un pin determinado con un nombre que le hemos dado asi como una instruccion con un nombre que tambien hemos predefinido:

LED_ON(LED1);LED_OFF(LED2);

Retardos

Que son los retardos.Los retardos son procesos que "no hacen nada" es decir solo se ejecutan por un tiempo para hacer tiempo antes de seguir a otra instrucción.Un tema algo complicado cuando se programa en ensamblador son los retardos ya es necesario hacer calculos que dependen de qeu crystal estas utilizando y en base a eso hacer tus rutinas de retardo.

Ejemplo:Queremos prender un led un segundo y que luego se apague, si ponemos lo siguiente con nuestras previas definiciones:

LED_ON(LED1);LED_OFF(LED1);

Será tan rapido que ni siquiera veremos que se ah prendido el LED, es por esto que utilizamos retardos, gracias al complilador CSS no

Page 5: USB interfaz

necesitamso ningun calculo ni crear nuestras propias rutinas de retardo, ya existen varias funciones que podemos llamar para hacer estos retardos:

delay_ms(500); Esta funcion hará que en donde la mandes llamar ahi se quedara por 500 mili segundos.delay_us(500); Esta funcion hará que en donde la mandes llamar ahi se quedara por 500 micro segundos.

Entonces bien si necesitamos que prenda y apague por un segundo seria así:

LED_ON(LED1);delay_ms(1000);LED_OFF(LED1);

Configuración de los puertos

Esto es básico al utilizar los microcontroladores, al principio de hacer cualquier instruccion en nuestro programa es necesario configurar nuestros puertos, tenemos que definir si serán salidas, entradas, o compartidos es decir que un puerto tenga como entradas los primeros dos pines y que todos los demas sean salidas. En CCS esto lo haremos con la siguiente instrucción.

Donde "value" es el numero hexadecimal, decimal o binario.set_tris_a (value);set_tris_b (value);set_tris_c (value);set_tris_d (value);set_tris_e (value);

Ejemplo quiero que el puerto A sean solo entradas, el puerto B solo salidas, y que el puerto D sean 4 entradas y 4 salidas.

set_tris_a(0xFF);set_tris_b(0);set_tris_d(0xF0);

Condicionales y Ciclos

Por lo regular en todo programa necesitamos de condiciones para pasar a otras instrucciones, y en ocasiones necesitamos que ciertas instrucciones se estén repitiendo o ya sea por un numero definido de veces ó que se un ciclo infinito. Con esto no hay mayor complicación es lo mismo que en C solo marcare lo que hay que saber para aplicarlo en CCS.

Condicional IF, el prototipo es sencillo:Si se cumple la condición se realiza la intrucción 1 en caso contrario se ejecuta la instrucción 2.

if (condicion) {Instruccion 1}

else {instruccion 2}

Donde la condición puede ser:

Una variable: Dato == 1 (La condicion seria SI Dato es igual 1 hacer isntruccion 1, si no es igual hacer instruccion 2)

El estado de un pin o puerto completo:Aplicando una instruccion dentro de la condición podremos preguntar por el estado de un pin osea que si esta en 1 logico o 0 logico.Ejemplo:

Page 6: USB interfaz

if (input(pin_D7)){output_bit(pin_D0, 1)}else {output_bit(pin_D0, 0)}

Analizando lo anterior, la condicion es, Si el pin 7 del puerto D se encuentra en 1 logico poner en 1 logico al pin D0, en caso contrario poner en 0 al pin D0.

Pero que pasa si queremos que nuestra condición sea que cuando el pin 7 este en 0 logico haga eso?, lo podemos hacer con otra instruccion además queremos que cuando este en cero el pin 7 pero tambien que solo entre si cumple con otra condicion mas se utiliza && , seria asi.

if (input_state(pin_D7) == 0 && input_state(pin_B0) == 1){output_bit(pin_D0, 1)}else {output_bit(pin_D0, 0)}

La condición seria... SI el pin 7 del puerto D esta en 0 Y el pin 0 del puerto B esta en 1, poner en 1 al pin 0 del puerto D en caso contrario poner en 0 al pin 0 del puerto D

Sencillo!! nada del otro mundo jaja xD

Ahora con los ciclos. El prototipo es sencillo tambiénEs, Mientras la condicion sea verdadera hacer las instrucciones 1,2 y 3.While(Condicion){Instrucción1Instrucción2Instrucción3}Ahora para el acople con CCS, para hacer un ciclo infinito la condicion seria:

While(TRUE){Instrucción1}

Para hacer ciclos qeu dependan de varibles o de los estados de los puestos se hace de la misma manera qeu las condiciones en la instrucción IF

Los FUSES (IMPORTANTE)

La palabra fuse viene a significar fusible. Sonará bastante raro, que un PIC pueda tener fusibles, pero nos sonará más familiar cuando comprendamos su funcionamiento. Hay ciertos aspectos del PIC que han de ser activados o desactivados mediante hardware a la hora de programarlo. Esto quiere decir que no se pueden volver a cambiar hasta que el chip no se reprograme de nuevo. Como no se pueden cambiar, de ahí le viene que sea como un fusible, el cual han fundido intencionadamente para proteger el modo de funcionamiento del procesador. Cada fuse activa o desactiva una opción de funcionamiento.

Page 7: USB interfaz

Entonces bien, para poder utilizar utilizar el Módulo USB del microntrolador es necesario tener la configuración de los Fuses correctamente ya que de lo contrario por mas que le busquemos por otros lados no funcionará. La configuración que se utilizó para este programa es la siguiente:

#fuses HSPLL,NOWDT,NOPROTECT,NOLVP,NODEBUG,USBDIV,PLL5,CP UDIV1,VREGEN

Ahora explicaré el porque de estos FUSES ya que luego vemos tutoriales y se explica todo y no explican lo que para ellos es Obvio, pero este no es el caso asi que vamos explicando:

HSPLL (High Speed PLL): Este Fuse se utuluza para cuando hemos de utilizar cristales mayores a 4MHZ y en este caso usaremos un cristal de 20Mhz.

NOWDT (No Watch Dog Timer): Este fuse se utiliza para deshabiliatar al "perro guardian" del microntrolador.

NOPROTECT: Como lo dice, este fuse es para desactivar la protección de lectura y escritura de nuestro PIC con el fin de proteger nuestro programa de piratas electronicos xD.

NOLVP (No Low Voltage Programing): Este Fuse aun me queda duda cuál es su principal función, si alguien sabe bien que me eche la mano :P.

NODEBUG (No Debug mode for ICD): No permite la utilización del modo debug.

USBDIV: significa que el Clock del Usb se tomará del PLL/2.

PLL5: Necesitamos que a nuestro micro le lleguen sólo 4MHz por lo que hay que usar un prescaler. Para ello en CCS se usa la sentencia PLLX, donde X significa la división de nuestro clock. Así pues si tenemos un cristal de 20MHz, el prescaler tendrá que ser 20 : 4 = 5 -> PLL5. Si por el contrario nuestro cristal es de 12MHz sería PLL3.

CPUDIV1: el PLL postscaler decide la división en 2 de la frecuencia de salida del PLL de 96MHZ, si queremos 48MHZ, lo dejaremos como está.

VREGEN: Habilita el regulador de 3.3 volts que usa el módulo USB

Esta configuración de los Fuses del microcontrolador siempre van al principio de nuestro programa, por eso se llaman directivas Pre compilador por ser las instrucciones iniciales de nuestro dispositivo y son las que se activarán al momento de que grabemos nuestro PIC.

Programación del Microcontrolador y Personalización de nuestro dispositivo USB

OK! Ya comprendido todo lo anterior podemos empezar a explicar lo que hace el programa ( que agregaré al final ), y como modificar la librería para que cuando inserten su dispositivo a la PC muestre el nombre que ustedes quieran que aparesca, Ejemplo. "Interfaz USB By Marck" en la descripción del dispositivo en windows.

Vamos primero a modificar la librería usb_kbd_HID.hpara la personalización.

Pueden abrir esta librería en CCS ó en algún Bloc de notas y se van hasta el final de la Libreria donde vean lo siguiente: USB_STRING_DESC[].

La tabla USB_STRING_DESC contiene la descripción del dispositivo detectado por el Driver de Windows XP y que nos va a mostrar en la correspondiente entrada en la lista del Hardware Instalado en el Sistema.

Consta de dos partes o tablas, la propiamente dicha USB_STRING_DESC que contiene las descripciones requeridas y una tabla accesoria llamada USB_STRING_DESC_OFFSET que contiene los offset, o desplazamientos con respecto al inicio de USB_STRING_DESC en donde se encuentran las correspondientes cadenas. Ambas constan de tres elementos cada una de ellas.

Page 8: USB interfaz

USB_STRING_DESC_OFFSET tiene tres números que indican cada uno de ellos donde comienza el correspondiente dato en la tabla USB_STRING_DESC. Así un contenido de {0,4,12} nos dice que que el primer string comienza en el byte 0, el segundo en el byte 4 y el tercero se encuentra a partir del byte número 12. Si cambiamos la longitud de cualquiera de los strings deberemos reordenar esta tabla correspondientemente con solo contar los caracteres y apuntar en esta tabla el número de byte donde comienza cada uno de ellos.

USB_STRING_DESC contiene los tres strings en concreto que deseamos transmitir con el descriptor USB. Cada uno de ellos tiene la misma estructura que consta de un primer byte que indica la longitud total de la correspondiente cadena, un segundo byte que indica el tipo de dato que viene a continuación y por último tantos bytes como sean necesarios como contenido del string.

El primer dato de esta tabla es:

4, USB_DES_STRING_TYPE, 0x09, 0x04 que puede leerse como 4 : Longitud en bytes del dato incluido él mismo. USB_DES_STRING_TYPE que es una constante cuyo valor e 3 y que dice que lo que sigue es un string. Y 0x09, 0x04 que le indica al Windows que los strings que siguen están escritos en correcto ingles americano (US-English)

Y los datos que nos importan son los siguientes dos de la tabla, a continuación muestro la imagen de mi modificación a estos valores y la explicación para que puedan modificar estos valores:

Cliquea esta barra para ver la imagen completa.

Si se fijan antes de cada String viene un numero que es la longitud que tendrá nuestro string ó cadena de caracteres. Este caso son 8 y 48 para el segundo string.

La longitud de la cadena tiene que ser exacta, sino saldrán caracteres que no tienen que ver con nuestro dispositivo si el número de la cadena es mayor o se suprimirán caracteres si el número de la cadena es inferior, para ello hay una fórmula muy sencilla que es:

(Número de letras + 1)*2 = longitud a poner

Ejemplo en string1 queremos poner MKA, esta tiene 3 caracteres por tanto:

longitud a poner = ( 3 + 1 ) * 2 = 4 + 2 = 8

Page 9: USB interfaz

Ejemplo en string2 queremos poner "USB 2.0 Marck Silencer.", contando espacios y el punto se tiene que son 23 caracteres por tanto:

Longitud a poner = (23 + 1) * 2 = 48

Hacen sus cambios en la longitud del string y el nombre que quieran y guardan la librería. Una vez hecho lo anterior esta librería la han de guardar en la carpeta "Drivers" de la carpeta donde instalaron el compilador CCS para después en el programa mandarla llamar con la directiva #Include.

Listo ahora con la explicación del programa Main.C Al abrir el proyecto en CCS, aparecerá lo siguiente:

Cliquea esta barra para ver la imagen completa.

Son las directivas pre compilador y algunas definiciones. A grandes rasgos, se incluyen las librerias que son necesarias para el manejo del USB así como la Libreria que hemos modificando anteriormente, los fuses que ya eh explicado. Si hay duda con esta parte decirla :P.

En esta parte no es mas que la declaración de las variables que usaremos nosotros directamente y las que usaran las funciones de las librerias USB de CSS.

Enseguida lo siguiente:

Esta es una función que será llamada constantemente durante nuestro programa principal (Main). Tiene como fin detectar que la PC ah enumerado nuestro dispositivo y enciendo un LED para indicarnos que la PC lo ah detectado correctamente este led se ah definido que estará en el PIN E0.

Despues:

Cliquea esta barra para ver la imagen completa.

Page 10: USB interfaz

Esta otra función que también es llamda constantemente en nuestro programa principal, es la que pregunta si hay nuevo dato, osea que si se ah presionado una tecla, si es así manda el dato a la computadora en dado caso de que no hay dato, se manda un 0 es decir nada. Esto porque se hace? según eh leído acerca del USB es necesario tener una comunicación constante entre el dispositivo y la computadora aunque no se este mandando ningún caractér ya que la computadora esta constantemente escaneando y si en algún momento dado ya no recibe aunque sea ese cero de no hay dato la computadora "piensa" que se ah desconectado el dispositivo, es por esto que es de suma importancia permanecer en comunicación con el Host ( computadora)

Despues:

Cliquea esta barra para ver la imagen completa.

Esta función es por si queremos recibir información de la computadora, en este caso no se utiliza esta función.

Despues:

Cliquea esta barra para ver la imagen completa.

Page 11: USB interfaz

En esta parte esta la función de interrupción que si bien se ah configurada la interrupción por cambio de estado en los pines R4 a RB7, cuando una tecla es presionada y fluye los 5 volts de uno de los renglones a uno de estos 4 puertos de interrupcion detecta este cambio de estado (de 0 a 1) y manda llamar a esta función, lo que hará será preguntar con las condiciones IF en cual de estos cuatro pines se ah cambiado de estado, y dependiendo de esto des pues preguntara nuevamente, y preguntara cual renglo ah hecho que cambiara de estado, y una vez detectado tanto el renglon como la columna, asignará a la variable "hay_dato" un 1 y guardará el codigo correspondiente a la tecla en la variable Dato. Esta variable "Hay_dato" es por la que pregunta la función usb_keyboard_task() para poder mandar el codigo guardado en Dato.

Cabe mencionar que la imagen las condiciones IF estan agrupadas para reducir espacio al visualizar el programa, es por esto que en el lado derecho hay un signo +, si damos clik sobre este más, se desplegara todo lo que esta dentro de ese IF

Y por fin nuestro Void Main:

Cliquea esta barra para ver la imagen completa.

Trate de poner los comentarios en el programa lo mas explicados. La primer parte solo son configuraciones e inicializacion de variables, activar interrupciones globales etc etc etc.

A simple vista podemos ver un ciclo WHILE que se ah puesto como infinito y dentro de este While una condición IF en la cual hacemos la rutina de recorrer los 5 volts por los 4 renglones, así como preguntar por los otros 3 botones, y preguntar por la columna 5, esta columna 5 no se pudo colocar como interrupcion como las otras 4 así que decidí colocarla en el puerto D0 y es necesario preguntar por ella, ya que no es como las otras columnas que trabajan como interrupción, entonces es de suma importancia estar preguntando si esta columna ah cambiado de estado de forma "manual", y en este IF también se mandan llamar a las funciones que preguntan si hay nuevo dato para mandar el codigo a la PC. En la imagen este IF aparece agrupado, para modificarlo bastaría con darle click en el signo + que aparece al lado izquierdo.