Está en la página 1de 133

2010

Primeros pasos con el 18F4550




www.unpocodelectronica.netau.net

[PRIMEROS PASOS CON EL
18F4550]
Manejo del PIC 18F4550 y puerto USB
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 2
Introduccin
Etapa Osciladora
Conociendo el PiN1 MCLR
PORTx vs LATx
Mdulo CAD o ADC (I)
Mdulo CAD o ADC (II)
Primera Prctica: PiCUSB
USB CDC (I)
USB CDC (II)
Monitorear el puerto COM virtual
Detectando el HOST (I)
Detectando el HOST (II)
Primera Aplicacin CDC
Conociendo al SnoopyPRO
mpusbapi.dll (I)
mpusbapi.dll (II)
mpusbapi.dll (III)
mpusbapi.dll (parte 4)
mpusbapi.dll (parte 5)
mpusbapi.dll (Primera Aplicacin)
Agradecimientos y Mritos Correspondientes

[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 3
Introduccin:
Mis Primeros pasos son una serie de artculos que describen la introduccin al mundo
de los uC-PIC 18F de Microchip, a travs del 18F4550.
el enfoque est orientado a aprender desde cero de alguien (el autor) que viene de
conocer y utilizar la serie uC-PIC 16F e intenta conocer poco a poco las nuevas
funcionalidades, caractersticas y mdulos que ofrece la serie 18F.
se empieza hablando sobre el aspecto fsico y analogas con el uC-PIC 16F877,
particularidades en pines, para despus entrar hablar, sobre el mdulo convertidor
analgico digital (ADC) y el mdulo estrella de 18F4550 como lo es Bus Serial
Universal (USB), donde se hace un estudio paso a paso para hacer las primeras
transmisiones, basndose en las libreras que provee el compilador de C de CCS.
como nota adicional, quisiera decir que esta serie de artculos de mis primeros pasos
con el 18F4550, fu escrita hace mas de 2 aos por lo que las ideas expresadas en sus
contenidos pueden estar estar obsoletas o fuera de carril.
He querido dejar casi intacto esta serie de artculos desde su origen, ya que la intencin
es mirar con la perspectiva de un novato la introduccin a los 18F tal como yo lo hice
cuando tuve en mis manos el primer 18F.
el enfoque de estos artculos, fu usando una redaccin un poco coloquial, mis excusas
para aquellos que sientan que no hay una redaccin propia de un artculo.
Configurando la Etapa Osciladora mediante los bits de Configuracin
(Fuses)
Lo primero que hice fue adaptar mi programador para este PIC, mi programador es por
puerto paralelo y lo use en conjuncin con el winpic800 de Sisco, para poder grabar el
18F4550.
-Lo segundo, meterme de cabeza en la datasheet a ver que cosas nuevas trae este seor,
respecto al anterior 16F877 (del cual vengo) y uff! si que trae una montaa de
caractersticas (features), en la pgina 4 de 39632c.pdf aparece el diagrama de los pines
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 4

Pinout del 18F4550
ya sabemos que el 18F4550 posee 40 pines, bien y por lo que se ve en la imagen, tiene
cierta similitud con el 16F877 (la misma ubicacin del pin vdd, vss, mclr entre otros)
el siguiente paso es saber como trabaja la configuracin del oscilador, en verdad a
primera vista con el diagrama del clock que aparece en la Pg. 26, parece complicado,
pero no es tan difcil, si se ve como si fuera el juego del laberinto, se pueden activar los
bits de los registros necesarios y as configurar el oscilador para el cristal que usemos y
el tiempo del ciclo de instruccin.
En la pgina de PicMana de Diego (RedPic) hay un artculo llamado: Consiguiendo 4
Mhz para los 48 Mhz necesarios en los PICs con USB 2.0, siguiendo las instrucciones
podemos configurar el CPU del 18F4550 a 48Mhz con solo seleccionar los word
configuration correctos.
como yo tengo un cristal de 4MHZ, lo usar para poner a trabajar el CPU a 48MHZ, y
porque 48 MHZ? claro! si se puede llegar hasta ah, entonces a trabajar al mximo!

segn la eleccin de mi cristal dibuj el camino a tomar para que la etapa del oscilador
tenga 48Mhz a la entrada del cpu, partiendo de los 4MHZ que le entran
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 5

Configuracin del modulo oscilador de 4MHz a 48Mhz

esto es necesario porque lo primero que debemos tomar en cuenta son los fuses que se
van a usar y la configuracin del oscilador forma parte de ello
para colocar el fuse de configuration y ya que es la primera vez, tomar prestado de la
que he visto en ex_usb_serial2.c que trae de ejemplo del compilador PCWH de CCS
1
2
3
4
5
6

...
//configure a 20MHz crystal to operate at 48MHz
#fuses
HSPLL,NOWDT,NOPROTECT,NOLVP,NODEBUG,USBDIV,PLL5,CPUDIV1,VREGEN
#use delay(clock=48000000)
...
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 6
esto hay que analizarlo, hay algunos conocidos y otros nuevos (que se van a explicar),
as que vayamos a la pgina 288 de la datasheet y al archivo cabecera 18F4550.h
HSPLL: para cristales >4MHZ usando el PLL, en el cdigo ejemplo como
XTAL=4MHZ -> se cambiar a XTPLL
MCLR: significa que el pin 1 cumplir la funcin de Master CLeaR (y como arranca
el PIC cuando no hay MCLR?)
USBDIV: significa que el clock del usb se tomar del PLL/2, para nuestro cdigo es
irrelevante, ya que no usaremos el mdulo USB, pero lo dejaremos (o es 1 es 0)
PLL5: significa que el PLL prescaler dividir en 5 la frecuencia del cristal, si uso el
cristal de 4MHZ no habr falta dividir por lo que se usar PLL1
CPUDIV1: el PLL postscaler decide la divisin 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 mdulo USB, no lo usaremos
por los momentos, se cambiar por NOVREGEN
existen mas fuses para configurar, y habra que determinar como el compilador
configura el resto
si miran el la pgina 288, notaran que existe mas de un configuration word
(especficamente 7), no como en 16F877 que haba solo uno.
bueno, nuestro fuse quedar as:
1
2

#fuses
XTPLL,MCLR,NOWDT,NOPROTECT,NOLVP,NODEBUG,USBDIV,PLL1,CPUDIV1,NOVREGEN
ahora viene escribir un cdigo sencillo para poner arrancar el PIC, el programita lo que
va a hacer es, encender y apagar el PORTB en intervalos de 1 seg. y para ello hay que
averiguar como est configurado por defecto cada pin, me refiero a esto, ya que he
manejado un poco el 16F877 y por ejemplo el pin RB3 siempre hay que configurarlo en
el fuse si se va a utilizar como i/o digital


al mirar la pgina 293 nos encontramos otro fuse:


PBADEN: PORTB A/D Enable bit
Cmo!?, el portb tiene funciones de entrada analgica?, pues sip, as que tambin
hay que meter esa opcin en el fuse. Vamos hacer una prueba, vamos a dejar tal cual
qued nuestro fuse, para ver como lo hace el compilador y lo sabremos cuando
carguemos el .hex en el winpic800
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 7
vamos a escribir este cdigo en lenguaje C de CCS (para facilitar el aprendizaje pero
sigo con el dilema si lo hago en C en asm, para conocer mejor al micro) y el
simulador ser el MPLAB-SIM, que podemos hacer, hasta la fecha en que escrib esto
el proteus todava no trae el 18F4550
1
2
3
4
5
6
7
8
9
1
0
1
1
1
2
1
3
1
4
1
5
1
6
1
7
1
8
1
9
2
0
2
1
2
2
2
3
2
4
2
5
2
6
2
7
2
8
2
9
3
0
3
1
3
2

// cdigo ejemplo para hacer funcionar por primera vez al PIC18F4550
mediante encendido
// y apagado de 8 leds conectado al PORTB en intervalos de 1 Seg
// 16-Dic-2006

#include <18f4550.h> //archivo de cabecera
#fuses
XTPLL,MCLR,NOWDT,NOPROTECT,NOLVP,NODEBUG,USBDIV,PLL1,CPUDIV1,NOVREGE
N
// el fuse que configuramos anteriormente
#use delay(clock=48000000)
// el clock que tendremos a la entrada del CPU

void main() {
set_tris_a(0x0); // configura los puertos como salidas
set_tris_b(0x0);
set_tris_c(0x0);
set_tris_d(0x0);
set_tris_e(0x0);
//----------------------------------
disable_interrupts(global);
disable_interrupts(int_timer1);
disable_interrupts(int_rda);
disable_interrupts(int_ext);
disable_interrupts(int_ext1);
disable_interrupts(int_ext2);
setup_adc_ports(NO_ANALOGS);
setup_adc(ADC_OFF);
setup_spi(FALSE);
setup_psp(PSP_DISABLED);
setup_comparator(NC_NC_NC_NC);
setup_vref(FALSE);
port_b_pullups(FALSE);
//---------------------------
output_a (0); // saca un nivel bajo de salida en los puertos
output_c (0);
output_d (0);
output_e (0);
while(1){
output_b (0); // saca un nivel bajo en el portb
delay_ms(1000); // retardo de 1 Seg
output_b (0xff); // saca un nivel alto en el portb
delay_ms(1000); // retardo de 1 Seg
}
}
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 8
3
3
3
4
3
5
3
6
3
7
3
8
3
9
4
0
4
1
4
2
4
3
las lineas que estn delimitadas, las saqu del cdigo _rtc.c que escribi RedPic, en
estas lineas se desactivan otros modulos, como por ejemplo el CAD, SPI, PSP, las
interrupciones y las resistencias de amarre que estn en el PORTB, para este PIC hay
que averiguar como estn configurados por defectos cada pin y all veremos si hace falta
habilitar deshabilitar ciertos modulos (esto se aplica tambin para los fuses)
Esto ltimo lo digo porque el simulador es una cosa y el funcionamiento real es otra, en
el caso de los fuses, nosotros podemos determinar la configuracin porque el winpic800
nos lo dir, pero en el caso de los mdulos activados o desactivados por defecto, no
siempre el simulador acertar, as que para estar seguros es mejor escribir las
configuraciones en el programa. (esperemos que con esas sea suficiente)
bueno, compilemos y simulemos a ver que tal.

Compilacin de salida del MPLAB
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 9
que bien nos compil exitosamente, vamos a cargar el MPLAB-SIM y abrimos tambin
la ventana de los SFR, para ir viendo como estn los registros que nos interesa y los que
nos pueden interferir.
nota: se me pas por alto, con los pasos que indica el wizard crean el proyecto para el
cdigo que estamos probando y despus configuran la frecuencia del CPU (los fuses no
hacen falta configurarlo, porque el MPLAB los carga del que ya habamos programado)
vamos a ver como qued el configuration bits

Bits de Configuracin en MPLAB
epa! aqu dice que el portb tiene algunas entradas analgicas, vamos a ver que dice el
temp18.lst (el listado que genera el compilador)
1
2
3
4
5
6
7
8
Configuration Fuses:
Word 1: 0220 XTPLL NOIESO NOFCMEN PLL1 CPUDIV1 USBDIV
Word 2: 1E1E BROWNOUT NOWDT BORV20 PUT WDT32768 NOVREGEN
RESERVED
Word 3: 8300 PBADEN CCP2C1 MCLR NOLPT1OSC RESERVED
Word 4: 0081 STVREN NODEBUG NOLVP NOXINST NOICPRT RESERVED
Word 5: C00F NOPROTECT NOCPD NOCPB
Word 6: E00F NOWRT NOWRTD NOWRTC NOWRTB
Word 7: 400F NOEBTR NOEBTRB


efectivamente est la opcin PBADEN, pues ya comprobamos que se debe colocar
NOPBADEN en fuse, si es que queremos que RB[4-0] funcione como salida digital.
el fuses quedar:
1
2

#fuses
XTPLL,MCLR,NOWDT,NOPROTECT,NOLVP,NODEBUG,USBDIV,PLL1,CPUDIV1,NOVREGEN
,NOPBADEN
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 10
compilamos y vemos nuevamente la ventana configuration bits

Bits de Configuracin Corregido
ahora si nos aparece los pines RB[4-0] como i/o digitales.
Si por ejemplo simulamos con la opcin PBADEN, vern como en el portb no habr
problemas, har lo que el cdigo le dice, pero cuando vayamos a probar el PIC, no ser
as. Se dan cuenta? hay que estar pendiente de esos detallitos que nos pueden causar
dolor de alma.
viendo los registros PORTB y uno nuevo, el LAT., vern que cambiarn de estado:

Simulacin Mplab
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 11

Tiempo en Mplab-SIM
en la ventana stopwatch, se observa que por cada lnea ejecutada ocurren mas de un
ciclo de reloj, esto es tpico del C, si queremos ver que ocurre en cada ciclo, nada mas
carguemos Disassembly Lisa y veremos el cdigo en C con su correspondiente asm

Listado en Ensamblador
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 12
una vez ya simulado y verificado, viene la parte crtica, y es la de programar el PIC,
montarlo en el protoboard y rezar para que funcione, podemos llegar a 2 resultados:

-Que si funciona y realmente nos llena de alegra y podemos dar el siguiente paso



Que no funciona y hay que volver a revisar todo nuevamente :-s
la segunda opcin es la frecuente y que no nos gusta mucho, pero es la que nos d el
conocimiento. Manos a la obra!
amigos, de buena suerte que todo funcion al primer arranque!! y es que se tomaron
las previsiones una y otra vez, antes de conectar el PIC, verifiqu niveles de tensin,
posicin de los pines, etc.
http://www.youtube.com/watch?v=Wlpz-R9b0pY
en realidad con este primer ejemplo lo que se pretende, es aprender a configurar el
oscilador y a configurar los fuses, que es lo bsico a la hora de programar un PIC.

[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 13
Conociendo el Pin1 MCLR
Vamos con el segundo ejemplo. Quedaron 2 dudas al aire, el MCLR y el nuevo
Registro de Funciones eSpeciales LATx.
vamos a tratar primero lo del MCLR.
donde busquen en la datasheet el MCLR, vern que hay una opcin para desactivarlo
(es es que si empieza desde el propio fuse) y lo que se me ocurre es que el PIC puede
trabajar sin el Master CLeaR , sin los 5 voltios reglamentarios y que si queremos hacer
un reset, ser por software, cuya instruccin existe (se llama RESET)
si ven en la Pg. 126 vern que RE3 solo puede funcionar como entrada digital, as que
tendremos que pegar un switch si queremos probarlo, (y vamos a colocarlo para que sea
un cero en condiciones iniciales).
voy a modificar un poco el ejemplo1, cambio el fuse a NOMCLR (y automticamente el
pin RE3 <- entrada) de manera que si lee un pulso alto se enciendan los leds del portb y
si lee un pulso bajo se activan los leds del portc.
otro detalle, leyendo la configuracin del portc, me encuentro con que no existe RC3 y
eso no es todo, RC4 y RC5 solo funcionan como entrada digital, parece que es el precio
a pagar por implementar nuevos mdulos ( ver Pg. 119)


El pin RC3 del 18F4550



Pines RC4, RC5 del 18F4550

vaya, vaya, como haremos. Bueno lo que se puede hacer es usar el resto de los pines que
si funcionan como salida digital. RC[7-6,2-0]
1
2
3
4
5
6
7
8
// cdigo ejemplo para hacer funcionar por segunda vez al PIC18F4550
mediante encendido
// y apagado de 8 leds conectado al PORTB y RE3 en intervalos de 1
Seg (sin usar el MCLR)
// 20-Dic-2006

#include <18f4550.h> //archivo de cabecera
#fuses
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 14
9
1
0
1
1
1
2
1
3
1
4
1
5
1
6
1
7
1
8
1
9
2
0
2
1
2
2
2
3
2
4
2
5
2
6
2
7
2
8
2
9
3
0
3
1
3
2
3
3
3
4
3
5
3
6
3
7
3
8
3
9
XTPLL,NOMCLR,NOWDT,NOPROTECT,NOLVP,NODEBUG,USBDIV,PLL1,CPUDIV1,NOVRE
GEN,NOPBADEN
#use delay(clock=48000000) // el clock que tendremos a la entrada
del CPU

void main() {
set_tris_a(0x0); // configura los puertos como salidas
set_tris_b(0x0);
set_tris_c(0x0);
set_tris_d(0x0);
// set_tris_e(7); // RE3 <- entrada no hace falta configurarlo
(ver note1 pag126)
//-----------------------------------
disable_interrupts(global);
disable_interrupts(int_timer1);
disable_interrupts(int_rda);
disable_interrupts(int_ext);
disable_interrupts(int_ext1);
disable_interrupts(int_ext2);
setup_adc_ports(NO_ANALOGS);
setup_adc(ADC_OFF);
setup_spi(FALSE);
setup_psp(PSP_DISABLED);
setup_comparator(NC_NC_NC_NC);
setup_vref(FALSE);
//-------------------------------------------
port_b_pullups(FALSE);
output_a (0); // saca un nivel bajo de salida en los puertos
output_b (0); // saca un nivel bajo en el portb
output_c (0);
output_d (0);
output_e (0);
while(1){
if(input_state(PIN_E3)){
output_b (0); // saca un nivel bajo en el portb
delay_ms(1000); // retardo de 1 Seg
output_b (0xff); // saca un nivel alto en el portb
delay_ms(1000);
}
else{
output_b (0); // saca un nivel bajo en el portb
output_c (0); // saca un nivel bajo en el portc
delay_ms(1000);
output_c (0xff); //saca un nivel alto en portc
delay_ms(1000);
}
}
}
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 15
4
0
4
1
4
2
4
3
4
4
4
5
4
6
4
7
4
8
4
9
5
0
en los pines no usados del portc, del ejemplo1, no le dimos importancia, pero RC[5-4]
estaban como entrada digital (segn el MPLAB el mdulo USB est deshabilitado por
defecto) y no nos dimos cuenta y dejamos esos pines al aire, para resolver esto, coloqu
unas resistencias de 1k a VSS


Nota acerca de RC4 y RC5 del 18F4550



despus de compilar exitosamente (gracias Dios, jeje) y verificar los fuses veremos en la
simulacin en MPLAB a ver que pinta tiene:
http://www.youtube.com/watch?v=anfwe__gnYc

[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 16
yo creo que no importa si limpiamos el TRISC, porque de todas manera RC[5-4]
quedaran como entradas, observen que en la simulacin aparecen esos pines como
salidas activndose (aunque el LATC aparece RC[5-3]<-0 raro no?), ya hice la prueba
y no encienden los leds para esos pines.
nota: el circuito para este ejemplo est en el adjunto, en el circuito del ejemplo1 omit
un componente que haba puesto en el protoboard, es un condensador de 100nF entre
VDD y VSS.
el montaje funcionando:
http://www.youtube.com/watch?v=YPHsHsEao10
el objetivo de este ejemplo fue el como trabajar el pin 1 del PIC 18F4550 y los detalles
que trae el portc
el adjunto con el cdigo fuente, circuito elctrico, etc.
PORTx vs LATx
-Qu es eso de LATA, LATB,..?- si miran en la pgina 71 de 39632c.pdf, tenemos del
LATA-LATE. La segunda que vemos el LAT es en la pgina 113 y ya empiezan a
especificar su funcionamiento, el LAT significa output latch salida del latch, si
comparamos una salida de este pic con uno del 16F877

El pin RC3 del 16F877
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 17

El pin RC3 del 18F4550
la diferencia principal que se ve all es el buffer RD LAT cuya funcin es leer el estado
de la salida del LAT (que funcin puede tener el leer la salida del LAT?) y WRLAT or
PORT en el clock, bueno amigos como el datasheet no d mayores explicaciones
porque dice que puede ser cualquiera de los 2. Puedo escribir en el pin usando
LATx,pin PORTB. As que consultando los links de arriba, todos coinciden: el
registro existe por cuestiones de rapidez al cambiar un flanco en un pin.
yo recuerdo que para evitar escrituras errneas en la familia 16F manejando bits se
recomienda colocar un nop entre pines:
1
2
3
bsf porta,0
nop
bsf porta,1
obviamente que la existencia del registro LATx es una mejora ya que en un ciclo de
instruccin garantizas la escritura en un pin del puerto, pero esto habra que
comprobarlo con un ejemplo
quera pegar este cdigo en ensamblador pero dentro de entorno C
1
2
3
4
#asm
bsf PORTB,0,1
bsf PORTB,1,1
#endasm
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 18
pero sospecho que el pcwh, mete sus narices an en asm, porque en la ayuda del ccs,
dice:


BSF f,b


cuando en realidad la instruccin es:


BSF f,b,a


donde a es un operando que tiene que ver con el tipo de acceso al banco de memoria
RAM (bueno, pero no se supone que la memoria RAM es lineal?), esa duda la
dejaremos pendiente por los momentos.
entonces lo mejor es ensamblar desde el mpasmwin y ya que vamos a usar el 100%
ensamblador, es bueno saber saber la configuracin de los puertos, para ello veremos la
inicializacin de los puertos que salen a partir de la Pag 113 (corresponde al captulo 10
I/O PORTS) y en la plantilla 4550temp.asm que est en la carpeta code dentro de
MPASM Suite
el archivo hlpPIC18ConfigSet.chm ensea como configurar los fuses
una nota curiosa vean la direccin sealada (viendo el listado en asm generado por el
CCS del ejemplo2)

Coincidencia
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 19
as ser de fea la programacin en asm para los 18F que el propio MPLAB me lo dice,
jaja
pero volviendo en serio, aqu vamos a tener que repetir un poco el ejemplo1, configurar
los fuses que ya no se llamaran fuses, sino word configuration, configuratin bits. (ver
Pag . 287)
La directiva de configuracin de palabras se puede escribir CONFIG y seguido los bits
involucrados (en 16F se escribe __CONFIG xx & yy &..) para mayor comodidad se
puede escribir CONFIG CP = OFF, OSC = LP,..
tomando el fuse del ejemplo1 nuestra palabra de configuracin quedar as:
CONFIG FOSC = XTPLL_XT, PLLDIV = 1,CPUDIV = OSC1_PLL2,USBDIV = 2,PWRT
= ON,BOR = SOFT, VREGEN = OFF , WDT = OFF ,WDTPS = 1,MCLRE = ON,PBADEN
= OFF
CONFIG LVP = OFF,XINST = OFF,DEBUG = OFF
aqu hay que escribirlos toditos, porque no se sabe como estan por defectos, pero sin
complicar mucho la explicacin lo que se hizo fu ver como el CCS configuraba los 7
word y llevarlos al asm, y eso fu lo que est arriba.
este ejemplo3 har lo siguiente:


-RB0 es un switche (normalmente en 0)
-si hay un cero en RB0-> se encendern los leds de RB[6,4,2]
-si hay un 1 en RB0-> se encendern los leds de RB[7,5,3,1]
-en cada caso se apagarn los leds no mencionados.


para la escritura del PORTB, primero se utilizar el clsico PORTB, a ver que sucede y
despus el LATB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
; cdigo ejemplo para hacer funcionar por tercera vez al PIC18F4550
mediante encendido
; y apagado de 8 leds conectado al PORTB dependiendo del estado del
pulsador en RB0
; que encender leds pares e impares
; 21-Dic-2006

LIST P=18F4550 ;directive to define processor
#include <P18F4550.INC> ;processor specific variable definitions

CONFIG FOSC = XTPLL_XT, PLLDIV = 1,CPUDIV = OSC1_PLL2,USBDIV =
2,PWRT = ON,BOR = SOFT, VREGEN = OFF
CONFIG WDT = OFF ,WDTPS = 1,MCLRE = ON,PBADEN = OFF,LVP = OFF,XINST
= OFF,DEBUG = OFF

CBLOCK 0x0

ENDC

org 0
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
goto inicio
; org 0x8 interrup alta priori
; org 0x18 baja prioridad
inicio:
; clrf LATA ; limpia los latch
; clrf LATB
; clrf LATC
; clrf LATD
; clrf LATE
clrf TRISA ; configuar el port como salida que bueno!, no hay
que estar cambiando de bancos ;-)
movlw 0x1
movwf TRISB ; configura RB0<- entrada, el resto -> salida
clrf TRISC
clrf TRISD
clrf TRISE
;//------------------------------------------------------
; ahora viene la deshabilitacin de modulos (pheriperals)
;*******************************************************
clrf,ADCON0 ; desactiva el CAD
movlw 0xf
movwf ADCON1 ; todas digitales
bcf INTCON,GIE ; desactiva interrupciones
movlw 0x7
movwf CMCON ;desactiva el modulo comparador
;clrf CVRCON ; desactiva el Vref del comparador no hace falta
clrf SPPCON ; desactiva el modulo Streaming Parallel Port (SPP)
clrf SSPCON1 ; desactiva el modulo MSSP,SSPEN
bcf UCON,USBEN ; desactiva el modulo USB
bsf INTCON2,RBPU ; desactiva las resistencias de amarre en PORTB
;//-------------------------------------------
ciclo:
btfss PORTB,0
bra LED_RB2
bcf PORTB,2,1
bcf PORTB,4,1
bcf PORTB,6,1

bsf PORTB,1,1
bsf PORTB,3,1
bsf PORTB,5,1
bsf PORTB,7,1
bra ciclo
LED_RB2:
bcf PORTB,1,1
bcf PORTB,3,1
bcf PORTB,5,1
bcf PORTB,7,1

bsf PORTB,2,1
bsf PORTB,4,1
bsf PORTB,6,1
bra ciclo
end
como pueden ver, en este cdigo se va a comprobar que pasa si usamos la instruccin
PORTB para manejar datos de salida y LATx
notas:
-por darmelas de vivo, trat de configurar el TRISB, as:
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 21


movff 01,TRISB


pero no sirve, porque para esa instruccin los argumentos deben ser registros en ambos
(ver pagina 334), nos vamos por el tradicional registro de trabajo, (que ahora se llama
WREG)
-hay otra instruccin nueva el BRA, suena al salto que se utiliza en BASIC (que sera
BRANCH) y porque no usamos el goto? bueno tambin sirve, una diferencia que le,
es que el goto puede saltar mas lejos, para nuestro ejemplo el BRA sirve, lo dejaremos.
ahora compilaremos el ejemplo3 y simularemos con el MPLAB (mirar con atencin la
ventana de la derecha, es la de Registros Funciones eSpeciales):
http://www.youtube.com/watch?v=uhYkxjsU6wU
el warning se debe a que la instruccin limpia un registro de solo 6 bits, los menos
significativos, pero no hay rollo.
en la simulacin vemos que ningn pin del puertoB cambia, ni el LATB, pero como yo
soy necio, voy a grabar ese mismo cdigo en el pic, haber que hace.
nota: la palabra de configuracin la compar con el del ejemplo1, e hice un cambio el
BOR=ON el watchdog, aunque cambi, no altera el programa.
el video en protoboard:
http://www.youtube.com/watch?v=tAMmVcAKKGk
Qu! y porque se quedan prendidos esos 3? vamonos a revisar el cdigo, parece que
hay un error en las instrucciones B(s/c)F, especificamente en el ltimo argumento, yo
les puse 1.
Ese argumento tiene que ver con el acceso al banco de memoria, si vemos un momento
el listado que genera el dissasembler:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
...
0004 6A92 CLRF 0xf92, ACCESS 29: clrf
TRISA ; configuar el port como salida que bueno!, no hay que
estar cambiando de bancos ;-)
0006 0E01 MOVLW 0x1 30: movlw 0x1
0008 6E93 MOVWF 0xf93, ACCESS 31: movwf
TRISB ; configura RB0<- entrada, el resto -> salida
000A 6A94 CLRF 0xf94, ACCESS 32: clrf
TRISC
000C 6A95 CLRF 0xf95, ACCESS 33: clrf
TRISD
000E 6A96 CLRF 0xf96, ACCESS 34: clrf
TRISE
35: ;//--------
----------------------------------------------
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 22
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
36: ; ahora
viene la deshabilitacin de modulos (pheriperals)
37:
;*******************************************************
0010 6A00 CLRF 0, ACCESS 38:
clrf,ADCON0 ; desactiva el CAD
0012 0E0F MOVLW 0xf 39: movlw 0xf
0014 6EC1 MOVWF 0xfc1, ACCESS 40: movwf
ADCON1 ; todas digitales
0016 9EF2 BCF 0xff2, 0x7, ACCESS 41: bcf
INTCON,GIE ; desactiva interrupciones
0018 0E07 MOVLW 0x7 42: movlw 0x7
001A 6EB4 MOVWF 0xfb4, ACCESS 43: movwf
CMCON ;desactiva el modulo comparador
44: ;clrf
CVRCON ; desactiva el Vref del comparador no hace falta
001C 6A65 CLRF 0xf65, ACCESS 45: clrf
SPPCON ; desactiva el modulo Streaming Parallel Port (SPP)
001E 6AC6 CLRF 0xfc6, ACCESS 46: clrf
SSPCON1 ; desactiva el modulo MSSP,SSPEN
0020 966D BCF 0xf6d, 0x3, ACCESS 47: bcf
UCON,USBEN ; desactiva el modulo USB
0022 8EF1 BSF 0xff1, 0x7, ACCESS 48: bsf
INTCON2,RBPU ; desactiva las resistencias de amarre en PORTB
49:
;disable_interrupts(global);
50:
;setup_adc_ports(NO_ANALOGS);
51:
;setup_adc(ADC_OFF);
52:
;setup_spi(FALSE);
53:
;setup_psp(PSP_DISABLED);
54:
;setup_comparator(NC_NC_NC_NC);
55:
;setup_vref(FALSE);
56: ;//--------
-----------------------------------
57:
;port_b_pullups(FALSE);
58:
59: ciclo:
0024 A081 BTFSS 0xf81, 0, ACCESS 60: btfss
PORTB,0
0026 D008 BRA 0x38 61: bra
LED_RB2
0028 9581 BCF 0x81, 0x2, BANKED 62: bcf
PORTB,2,1
002A 9981 BCF 0x81, 0x4, BANKED 63: bcf
PORTB,4,1
002C 9D81 BCF 0x81, 0x6, BANKED 64: bcf
PORTB,6,1
65:
002E 8381 BSF 0x81, 0x1, BANKED 66: bsf
PORTB,1,1
0030 8781 BSF 0x81, 0x3, BANKED 67: bsf
PORTB,3,1
0032 8B81 BSF 0x81, 0x5, BANKED 68: bsf
PORTB,5,1
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 23
0034 8F81 BSF 0x81, 0x7, BANKED 69: bsf
PORTB,7,1
0036 D7F6 BRA 0x24 70: bra ciclo
71: LED_RB2:
0038 9381 BCF 0x81, 0x1, BANKED 72: bcf
PORTB,1,1
003A 9781 BCF 0x81, 0x3, BANKED 73: bcf
PORTB,3,1
003C 9B81 BCF 0x81, 0x5, BANKED 74: bcf
PORTB,5,1
003E 9F81 BCF 0x81, 0x7, BANKED 75: bcf
PORTB,7,1
76:
0040 8581 BSF 0x81, 0x2, BANKED 77: bsf
PORTB,2,1
0042 8981 BSF 0x81, 0x4, BANKED 78: bsf
PORTB,4,1
0044 8D81 BSF 0x81, 0x6, BANKED 79: bsf
PORTB,6,1
0046 D7EE BRA 0x24 80: bra ciclo
vemos que hay varias instrucciones que tienen un tercer argumento, este argumento
define como se va a accesar al banco de memoria RAM. En la pagina 66 aparece el
mapa de la memoria de datos
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 24

mapa de la memoria
la memoria se divide en bancos y dependiendo de un tal BSR(registro selector de
banco) se puede accesar a diferentes direcciones.
como esto es un tema aparte(que apenas estoy conociendo), solo dir, que por defecto el
tercer argumento es 0 como lo llama el mpasmwin (y el CCS tambin): ACCESS.
Es vlido si no se coloca nada, el MPLAB, lo asume como a=0 (ver pagina 67)
se colocar 0 en todas los B(s/c)F y el cdigo quedar as:
1
2
3
; cdigo ejemplo para hacer funcionar por tercera vez al PIC18F4550
mediante encendido
; y apagado de 8 leds conectado al PORTB dependiendo del estado del
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 25
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
pulsador en RB0
; que encender leds pares e impares
; 21-Dic-2006

LIST P=18F4550 ;directive to define processor
#include <P18F4550.INC> ;processor specific variable definitions

CONFIG FOSC = XTPLL_XT, PLLDIV = 1,CPUDIV = OSC1_PLL2,USBDIV =
2,PWRT = ON,BOR = ON, VREGEN = OFF
CONFIG WDT = OFF ,WDTPS = 1,MCLRE = ON,PBADEN = OFF,LVP = OFF,XINST
= OFF,DEBUG = OFF

CBLOCK 0x0

ENDC

org 0
goto inicio
; org 0x8 interrup alta priori
; org 0x18 baja prioridad
inicio:
; clrf LATA ; limpia los latch
; clrf LATB
; clrf LATC
; clrf LATD
; clrf LATE
clrf TRISA ; configuar el port como salida que bueno!, no hay
que estar cambiando de bancos ;-)
movlw 0x1
movwf TRISB ; configura RB0<- entrada, el resto -> salida
clrf TRISC
clrf TRISD
clrf TRISE
;//------------------------------------------------------
; ahora viene la deshabilitacin de modulos (pheriperals)
;*******************************************************
clrf,ADCON0 ; desactiva el CAD
movlw 0xf
movwf ADCON1 ; todas digitales
bcf INTCON,GIE ; desactiva interrupciones
movlw 0x7
movwf CMCON ;desactiva el modulo comparador
;clrf CVRCON ; desactiva el Vref del comparador no hace falta
clrf SPPCON ; desactiva el modulo Streaming Parallel Port (SPP)
clrf SSPCON1 ; desactiva el modulo MSSP,SSPEN
bcf UCON,USBEN ; desactiva el modulo USB
bsf INTCON2,RBPU ; desactiva las resistencias de amarre en PORTB
ciclo:
btfss PORTB,0
bra LED_RB2
bcf PORTB,2,0
bcf PORTB,4,0
bcf PORTB,6,0

bsf PORTB,1,0
bsf PORTB,3,0
bsf PORTB,5,0
bsf PORTB,7,0
bra ciclo
LED_RB2:
bcf PORTB,1,0
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 26
65
66
67
68
bcf PORTB,3,0
bcf PORTB,5,0
bcf PORTB,7,0

bsf PORTB,2,0
bsf PORTB,4,0
bsf PORTB,6,0
bra ciclo
end
haciendo la simulacin (mirar con atencin la ventana de la derecha, es la de Registros
Funciones eSpeciales):
http://www.youtube.com/watch?v=m-7uVP1ji6w
all muestra que el PORTB cambia los estados de acuerdo a la programacin escrita, ahora
procedemos a grabar el pic y ver el comportamiento
http://www.youtube.com/watch?v=AwaivT3Fg3g
ahora si hace lo que tiene que hacer, encender los leds pares e impares dependiendo del
switcheo. pero entonces quiere decir que si se puede trabajar con el PORTB como
salida.
vamos a tomar el otro caso, sustituiremos el PORTB por LATB en la escritura de los
pines de salida (llamemos ejemplo3_lat).
el cdigo cambiar as:
1
2
3
4
5
6
7
8
9
1
0
1
1
1
2
1
3
1
4
1
5
1
6
1
7
1
8
; cdigo ejemplo para hacer funcionar por tercera vez al PIC18F4550
mediante encendido
; y apagado de 8 leds conectado al PORTB dependiendo del estado del
pulsador en RB0
; que encender leds pares e impares
; 21-Dic-2006

LIST P=18F4550 ;directive to define processor
#include <P18F4550.INC> ;processor specific variable definitions

;#fuses
XTPLL,MCLR,NOWDT,NOPROTECT,NOLVP,NODEBUG,USBDIV,PLL1,CPUDIV1,NOVREGE
N,NOPBADEN // el fuse que configuramos anteriormente (CORREGIDO)
;#use delay(clock=48000000) // el clock que tendremos a la entrada
del CPU

CONFIG FOSC = XTPLL_XT, PLLDIV = 1,CPUDIV = OSC1_PLL2,USBDIV =
2,PWRT = ON,BOR = ON, VREGEN = OFF
CONFIG WDT = OFF ,WDTPS = 1,MCLRE = ON,PBADEN = OFF,LVP = OFF,XINST
= OFF,DEBUG = OFF

CBLOCK 0x0

ENDC

org 0
goto inicio
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 27
1
9
2
0
2
1
2
2
2
3
2
4
2
5
2
6
2
7
2
8
2
9
3
0
3
1
3
2
3
3
3
4
3
5
3
6
3
7
3
8
3
9
4
0
4
1
4
2
4
3
4
4
4
5
4
6
4
7
4
8
4
; org 0x8 interrup alta priori
; org 0x18 baja prioridad
inicio:
; clrf LATA ; limpia los latch
; clrf LATB
; clrf LATC
; clrf LATD
; clrf LATE
clrf TRISA ; configuar el port como salida que bueno!, no hay
que estar cambiando de bancos ;-)
movlw 0x1
movwf TRISB ; configura RB0<- entrada, el resto -> salida
clrf TRISC
clrf TRISD
clrf TRISE
;//------------------------------------------------------
; ahora viene la deshabilitacin de modulos (pheriperals)
;*******************************************************
clrf,ADCON0 ; desactiva el CAD
movlw 0xf
movwf ADCON1 ; todas digitales
bcf INTCON,GIE ; desactiva interrupciones
movlw 0x7
movwf CMCON ;desactiva el modulo comparador
;clrf CVRCON ; desactiva el Vref del comparador no hace falta
clrf SPPCON ; desactiva el modulo Streaming Parallel Port (SPP)
clrf SSPCON1 ; desactiva el modulo MSSP,SSPEN
bcf UCON,USBEN ; desactiva el modulo USB
bsf INTCON2,RBPU ; desactiva las resistencias de amarre en PORTB
;disable_interrupts(global);
;setup_adc_ports(NO_ANALOGS);
;setup_adc(ADC_OFF);
;setup_spi(FALSE);
;setup_psp(PSP_DISABLED);
;setup_comparator(NC_NC_NC_NC);
;setup_vref(FALSE);
;//-------------------------------------------
;port_b_pullups(FALSE);

ciclo:
btfss PORTB,0
bra LED_RB2
bcf LATB,2,0
bcf LATB,4,0
bcf LATB,6,0

bsf LATB,1,0
bsf LATB,3,0
bsf LATB,5,0
bsf LATB,7,0
bra ciclo
LED_RB2:
bcf LATB,1,0
bcf LATB,3,0
bcf LATB,5,0
bcf LATB,7,0

bsf LATB,2,0
bsf LATB,4,0
bsf LATB,6,0
bra ciclo
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 28
9
5
0
5
1
5
2
5
3
5
4
5
5
5
6
5
7
5
8
5
9
6
0
6
1
6
2
6
3
6
4
6
5
6
6
6
7
6
8
6
9
7
0
7
1
7
2
7
3
7
4
7
5
7
6
7
7
7
8
7
9
end
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 29
8
0
8
1
haciendo de nuevo la simulacin: (mirar con atencin la ventana de la derecha, es la de
Registros Funciones eSpeciales)
http://www.youtube.com/watch?v=6ysIB7npYao
el puerto B se escribe como debe ser, muy bien. Ahora a quemar el pic y probar en el
protoboard
http://www.youtube.com/watch?v=S559xGjpR6g
obtenemos el mismo resultado.
La conclusin de este tercer ejemplo, bueno la verdad es que no se pudo demostrar el
uso/comportamiento del PORTX frente al LATx, como escritura a los pines, creo que
eso lo dir la experiencia, ensayando y programando con el pic como ya lo han hecho
los que saben sobre el tema.

[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 30
Mdulo CAD o ADC (Parte1)
Usando el Mdulo del Convertidor Analgico Digital (CAD ADC en ingls)
Esta vez vamos a utilizar un mdulo que se utiliza frecuentemente: el mdulo del
Convertidor Analgico Digital(CAD ADC en ingls), yo he realizado uno que otro
montaje con este mdulo, pero nunca lo he explicado (por all dijeron que es mas difcil
explicar que aplicar lo aprendido), as que intentar aportar de lo que estoy conociendo.
las fuentes consultadas:
-PICmicro 18C MCU Family Reference Manual (39500a.pdf pgina 583)
-configurar el estmulo del ADRESL
-Conceptos
-SALTO EN EL CONVERTIDOR A/D DE UN 16F877
-convertir 10 bits y quedarme con 8
nos vamos directo para la pgina 261 del 39632c.pdf, que es el datasheet del la familia
PIC18F2455/2550/4455/4550 y all est un captulo dedicado a este mdulo.
-las diferencias que le respecto al 16F877, le agregaron un adcon2 y hay 13 posibles
entradas analgicas multiplexadas.
-la configuracin PCFG3:PCFG0 luce mas ordenada.
-Le agregaron unos bits que son muy interesantes ACQT2:ACQT0 para manejar el
tiempo de adquisicin, ya lo explicaremos.
- desde el punto de vista del 16F87xA(dentro de la familia 16) no ha cambiado las
opciones del clock de CAD (hay 7 opciones)
Quisiera hacer un resumen del funcionamiento del CAD para poder explicar las nuevas
opciones que trae el 18F4550 y las mejoras respecto al 16F877
La definicin del Convertidor Analgico Digital, la podemos conseguir en la wikipic y
se puede desglosar de la siguiente manera:
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 31

Circuito entrada analgica

de acuerdo a la imagen anterior:
-existen unos pines que se pueden configurar como entrada analgica, del cual se toma
uno a la vez.
-dado un arreglo R-C,que existe dentro, o a la entrada del mdulo CAD se toma un
nivel de tensin en un tiempo discreto, ese voltaje se almacenar en el condensador
interno (Chold)
-el tiempo que tarde ese condensador en cargarse, lo determinaremos nosotros de 2
maneras:
-mediante un retardo por software (configurando un timer, generando ciclos de
instruccin.
-mediante un retardo por hardware (configurando los bits ACQT2:ACQT0 en
ADCON2)
este tiempo, es el tiempo de adquisicin Tacq (acquire), y es fundamental para obtener
precisin en el resultado digital. Ojo no confundir con Tad, como lo hice alguna vez,
(las iniciales en ingls se asemejan a las iniciales en espaol).
en el caso del 16F877, mediante clculos tericos era Tacq ~ 20uS

Tiempo de Adquisicin 16F877
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 32
en el caso del 18F4550, el tiempo mnimo que sacan es Tacq ~ 2,45uS

Tiempo de Adquisicin 18F4550
esto aparece en la pgina 266. Se nota que disminuy el tiempo y aumentando as la
velocidad en el CAD
el retardo por hardware (que as lo quise llamar) programmable acquisition time es
algo nuevo, es posible configurar el Tacq:

Diferencias de ciclos de Tacq
en la figura 21-4 es como siempre lo habiamos visto, antes de activar el GO_DONE
haba que introducir el Tacq. Ahora usando la configuracin por hardware, tenemos la
figura 21-5 donde sucede despus de haber seteado al GO_DONE (no algodn, )),
hacindolo automtico.
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 33
-luego viene el proceso de hacer la conversin, es decir, tomar el valor analgico de lo
que est cargado en el condensador Chold y llevarlo a un nmero binario.
-en este proceso de conversin hay otros parmetros, uno de ellos es el reloj de
conversin,
esto quiere decir que el mdulo CAD, trabaja con un reloj distinto del CPU y que puede
depender o no de ste. Eso lo dir la debida configuracin de los bits ADCS2:ADCS0
del registro ADCON2
Cuando digo que puede ser independiente del CPU, es porque puede trabajar con un
reloj interno (un oscilador RC) cuya aplicacin sera poner a dormir el PIC mientras se
est haciendo una conversin, y que utilidad puede tener esto?, bueno al estar
trabajando solo el mdulo CAD, se reduce el ruido de conmutacin de los otros
perifricos y puede aumentar la precisin del valor digital obtenido.
Desventajas: usando el oscilador interno se tarda mas la conversin (en el orden de los
mS, que podra sera mucho tiempo para algunos eventos)
cuando inicia la conversin, lo primero que hace es desconectar el condensador Chold
de la entrada analgica, y mediante una aproximacin sucesiva, se v guardando bit a
bit de los 10 bits que hay, el resultado digital (ver figura 21-4)
esto tambin tiene su tiempo y es el tiempo (retardo) de conversin analgico digital por
bit, llamado Tad. Segn la pagina 267 se requiere de un tiempo de 11Tad para realizar
una conversin, el Tad mnimo para el CAD del 18F4550 es 700nS(pagina 400)
pero haciendo algunos clculos de acuerdo a la tabla 21-1

Frecuencia Operacin Tad
usando un clock del CPU de 48Mhz se obtiene hasta 64/48Mhz = 1.33uS
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 34

Secuencia Conversin A/D
Nota: el Tacq sacado por hardware depende de Tad

Bits seleccin Tacq
posteriormente viene todo lo que se venia aplicando anteriormente, esperar a que
GO_DONE =0 esperar la interrupcin del CAD y tomar el valor que est en la pareja
de bytes ADRESH:ADRESL (limpiar la bandera ADIF si es es por interrupcin) en
general, los pasos para un CAD, serian (Pg. 265):
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 35

pasos requeridos para realizar una conversin
desde luego que todo esto es pura teora, as que vamos a darle con un ejemplo
para nuestro ejemplo (ejemplo4):
-usaremos un reloj de conversin de 64Tosc = Fosc/64 ya que seguiremos usando un
clock de 48Mhz y esto es lo que recomienda la tabla 21-1
-usaremos el Tacq por hardware, as que si nuestro Tad= 1.33uS, entonces usando un
tacq= 2Tad= 2*1.33uS = 2.66uS
-seleccionaremos el canal AN0, el resto como i/o digital.
-haremos la conversin AD y despus indicaremos el resultado en 10 leds.
aunque yo no se para que tanta precisin, si estoy trabajando en C, y no se que como
har eso el compilador.
clculo preciso + clculo(terico)= clculo preciso + error ( prctico)
clculo preciso + error ( terico)= clculo preciso + error ( prctico) + error ( terico)
1
2
// usando el CAD en el 18F4550
// 30-Dic-2006
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 36
3
4
5
6
7
8
9
1
0
1
1
1
2
1
3
1
4
1
5
1
6
1
7
1
8
1
9
2
0
2
1
2
2
2
3
2
4
2
5
2
6
2
7
2
8
2
9
3
0
3
1
3
2
3
3
3
4
3
5
3
6
#include <18f4550.h> //archivo de cabecera
//#DEVICE ADC=8 // cad a 8 bits, justificacin a a la derecha
#DEVICE ADC=10 // cad a 10 bits, justificacin a a la derecha
//#DEVICE ADC=16 // cad a 10 bits, justificacin a a la izquierda
#fuses
XTPLL,MCLR,NOWDT,NOPROTECT,NOLVP,NODEBUG,USBDIV,PLL1,CPUDIV1,NOVREGE
N,NOPBADEN // el fuse que configuramos anteriormente (CORREGIDO)
#use delay(clock=48000000) // el clock que tendremos a la entrada
del CPU

#byte LATB=0xF8A
#byte PORTB=0XF81

void main() {
long value;
int parte_alta;
int ADC_ACQT_2TAD=0x1;
output_a(0); // saca un nivel bajo de salida en los puertos
output_b(0);
output_c(0);
output_d(0);
output_e(0);
set_tris_a(0x1); // configura los puertos como salidas
set_tris_b(0x0);
set_tris_c(0x0);
set_tris_d(0x0);
set_tris_e(0x0);
//-----------------------------------
disable_interrupts(global);
disable_interrupts(int_timer1);
disable_interrupts(int_rda);
disable_interrupts(int_ext);
disable_interrupts(int_ext1);
disable_interrupts(int_ext2);
setup_spi(FALSE);
setup_psp(PSP_DISABLED);
setup_comparator(NC_NC_NC_NC);
setup_vref(FALSE);
port_b_pullups(FALSE);

setup_adc_ports( AN0 || VSS_VDD );
setup_adc(ADC_CLOCK_DIV_64 || ADC_ACQT_2TAD );
set_adc_channel(0);
while(1){ // bucle infinito
value = read_adc(); // toma el resultado del CAD
output_b((int)value); // enva el byte LSB a portb
parte_alta=(int)((value & 0x300)>>8); // separa los 2 bits MSB de
value
output_c(parte_alta); // y los envia al portc
}
}
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 37
3
7
3
8
3
9
4
0
4
1
4
2
4
3
4
4
4
5
4
6
4
7
4
8
4
9
buscando en el CCS no consegu alguna constante declarada para los bits ACQTx as
que tuve que crearlos y hacer una OR incluyente con las dems constantes dentro de la
funcin setup_adc().


int ADC_ACQT_2TAD=01;


para comprobar si esto es correcto, voy a compilar y mirar en la ventana SFR del
MPLAB para ver como qued el registro ADCON2
http://www.youtube.com/watch?v=wI9DlXFLGEI
Pero fue en vano, el CCS no me deja cambiar los bits 3,4,5 de ADCON2, as que me
voy por ensamblador, sustituyo la lnea setup_adc(ADC_CLOCK_DIV_64 ||
ADC_ACQT_2TAD ); por:
1
2
3
4
#asm
movlw 0b10001110 ;justificacion_derecha,2Tad,Fosc/64
movwf 0xFC0 ; direccion de ADCON2
#endasm
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 38

ahora si acept el cambio, entonces se hace la simulacin nuevamente, pero antes
introduzco el cambio de ADRESx mediante estmulos, en una de las fuentes consultadas
( ver arriba) el amigo Maunix explica como hacerlo, ahora si arrancamos con el
MPLAB-SIM
http://www.youtube.com/watch?v=Fzf2_wvbiQU
el estmulo no est funcionando, de verdad que pas un rato creyendo que estaba mal
configurado el Register Injection, pero despus me di cuenta que faltaba la instruccin
setup_adc(), si as como lo leen, como se hace entonces si lo haba quitado?, bueno, lo
coloque de nuevo y le aad el pedacito en assembler para que aceptara el cambio en
ADCON2
1
2
3
4
5
setup_adc(ADC_CLOCK_DIV_64 );//|| ADC_ACQT_2TAD );
#asm
movlw 0b10001110 ;justificacion_derecha,2Tad,Fosc/64
iorwf 0xFC0,1 ; direccion de ADCON2
#endasm
claro, que cambi el movwf por iorwf, para que me aceptara los nuevos bits sin alterar
el estado anterior de ADCON2,
tambin es bueno decir que por aqu se puede cambiar la justificacin, hay otra cosa
interesante, en CCS hay una directiva #DEVICE ADC=xx , sera bueno analizar que
pasa si cambio ADC=10 por ADC=16, esto har la justificacin hacia la izquierda?,
sera otro estudio.
vamos a simular de nuevo,
nota: el archivito llamado adresito.txt tiene estas lneas guardadas:


1A0
2AA
3FF
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 39


esas lneas corresponden al supuesto valor de ADRESH:ADRESL y sern cargadas por
el estmulo en un bucle
http://www.youtube.com/watch?v=H4ozbfY1PGY
me dio curiosidad y v el listado en ensamblador, met un breakpoint en el momento de
escoger el canal y hasta que se cargan la pareja ADRESH:ADRESL

Tiempo muestra medido en MPLAB-SIM
calculando el tiempo terico: Tacq= 2*Tad + 11*Tad= 2*(64/48Mhz)
+11*(64/48Mhz)=17.33uS bastante aproximado con los 18.33 uS que d el MPLAB-
SIM.
el siguiente paso es programar el PIC y probarlo en el protoboard, hay un detallito que
se est olvidando,la resistencia Rs, que es la que v a la entrada AN0, segn los clculos
tericos mximo de 2.5k, yo usar un potencimetro que le med 2k que es lo que tengo
a mano, habr algn cambio? eso habr que verlo en el protoboard.
ja ja con tanta cablamenta, me imagino el ruido que debe haber all.
Lo importante es que hicimos arrancar el mdulo CAD y que hicieras las respectivas
conversiones.
hice unas mediciones con el tester, y me di cuenta que al insertar la punta en AN0
parece que introduce variaciones, as que conect un TL082 como seguidor de voltaje,
para poder medir sin interferencias. peeeero me top con un problemita, hay un detalle
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 40
cuando intentas medir niveles cercano a 0 volts usando el TL082. Buscando por ah
consegu una pgina donde explican el fenmeno (llamado latch-up), a mi me sucede
esto porque alimento al operacional con +Vcc=+5 y -Vcc=0.
Solucin: aliment al operacional con +Vcc=+12 y -Vcc= -12 y listo!.
volv hacer mediciones, esta vez arreglando mejor las conexiones:
- una especie de apantallamiento a la entrada AN0
- acerqu mas el C=100nF de alimentacin del PIC.
y varios resultados obtenidos:

datos obtenidos tabulados
segn estos datos obtenidos, la precisin es mas o menos uhmmm, ser por el
montaje en protoboard, si ya se que todo es relativo voy hacer otra prueba, voy a
aumentar el Tacq al mximo permitido por ADCON2, esto es 20Tad = 20 * 1.33uS =
26.6 uS bastante tiempo de sobra que sumndole 11Tad = 11* 1.33uS =14.63uS dara
una conversin aproximada de 41.23uS
para Tacq=20Tad -> ADCON2<-0b10111110, entonces el cdigo cambiar:
1
2
3
4
#asm
movlw 0b10111110 ;justificacion_derecha,20Tad,Fosc/64
iorwf 0xFC0,1 ; direccion de ADCON2
#endasm
repitiendo todo el procedimiento anterior, compilando y simulando y despus grabar el
micro, llegamos a revisar el montaje en el protoboard:
y unos datos nuevos que recopil
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 41

Segunda recopilacin datos
Conclusin:
Bueno seores, esos resultados como que mejoraron un poco, uhmmmm la verdad es
que nunca he podido obtener valores calculados en la prctica, quizs un montaje mejor
elaborado en baquelita y bien filtrado pueda aumentar la precisin.
espero que les pueda instruir en algo.
Mdulo CAD o ADC (Parte 2)
Continuando con el CAD, segu haciendo varias mediciones con el cdigo realizado
anteriormente y descubr nuevos detalles
- segn la pgina 602 de 39500a.pdf

Colocar condensador 100nF en AN0
all recomiendan colocar un condensador de 100nF a la entrada de AN0 si la seal no
cambia tan rapidamente, a mi me sirve pues estoy variando con un destornillador y eso
es mas lento que inyectar una seal de baja frecuencia.
-para la alimentacin en AN0, us un 7805 aparte, para separar los voltajes.
-not una variacin de Vdd, no se porque la alimentacin del 7805 cambia cuando varo
el potencimetro en AN0, as que en las mediciones tom en cuenta ese valor de Vdd
que es mi Vref, en cada dato que sacaban los leds.
los nuevos datos obtenidos:
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 42

nuevos datos

valor prctico vs calculado
segn la grfica se nota una mejora en la precisin, pero yo sigo obstinado a conseguir
mas precisin, despus de un buen rato debugeando con el MPLAB SIM, observ la
pestaa MPLAB SIM que est adentro de la ventana OUTPUT y me sala este mensaje:
1
2
ADC-W0001: Tad time is less than 1.60us
ADC-W0010: A Minimum of 2 TADs are required before another conversion
should be started.
-el primer mensaje es cierto porque el ADCON2 est para FOSC/64 = 1.33uS, pero
recuerden que me estoy guiando por las recomendaciones de la datasheet.
-con el segundo mensaje, el MPLAB SIM me di un regao, muy cierto me salt esos
tiempos:
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 43

Tiempo mnimo Tad
esto sale en la pgina 265
3Tad = 3*(64/48MHZ)=3.99uS
entonces modifiqu el programa, metiendo un delay_us(5) y grab el pic, y volv a
tomar datos, pero un momento! en la pgina 268 dice que pueden ser 2Tad:

Tiempo mnimo 2Tad
yo con mi mana lo saqu para ambos valores(2Tad y 3Tad) y aqu estan los resultados:
para tiempo entre muestras >= 2Tad:

tabla de datos para 3uS
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 44

Muestra 3uS prctico vs calculado
para tiempo entre muestras >= 3Tad:

tabla datos para 5us

[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 45
Muestra 5uS prctico vs calculado
Ahhh!!! se dan cuenta seoras y seores, los valores son cercanos a lo calculado, o
sea, que ese tiempito entre conversin y conversin es MUUY IMPORTANTE y yo
voy a seguir sacandole punta a este ejemplo (que ahora se llama ejemplo4_parte2).
nota:
-esto ya se sale de la iniciacin con el 18F4550, formara parte de la configuracin
bsica de un mdulo CAD.
-observen en los resultados que la variacin de Vdd fu muy poca !?!?
voy a modificarlo como quera en un principio, tratar que el CAD se tarde lo mnimo en
hacer una conversin, es decir, con Tacq=2Tad y un 2Tad entre muestras, para ellos
cambiamos por estas lineas:
1
2
3
4
5
6
#asm
movlw 0b10001110 //justificacion_derecha,2Tad,Fosc/64
...
...
delay_us(3); // para pasar >= 2Tad a la sig CAD
...
y una vez mas, empiezo a tabular datos, jeje

tabla de datos Tacq y 2Tad para 3uS
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 46

datos obtenidos Tacq y 2Tad para 3uS
de estos ultimos resultados tengo varias conclusiones:
-que si es posible hacer un conversin con aceptable precisin, usando el mnimo
tiempo de la Adquisicin por hardware.
-que el Vdd variaba (y esto es una sospecha) debido a incremento de corriente de parte
de los leds, noten en los datos que a medida que mas leds se encendian, Vdd iba
disminuyendo, esto no tiene que ver con la configuracin del CAD.
-que hay que estar pendiente con los minimos detalles que dicen en la datasheet, tal es el
caso del mnimo Tad entre muestras.
-que no se le puede exigir demasiado a un montaje en protoboard.

[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 47
Primera Prctica: PiCUSB
Ahora vamos a hablar del mdulo USB, Esto si es nuevo para mi y como la fiebre es
tan grande me salt todas las barreras y me fu derechito con el ejemplo del amigo
Jaime J1M, el del encender un par de leds. As que voy a describir esta pequea
aventura, como para la bajar la fiebre un poco.
bien, el primer paso, conseguir el cdigo del PicUSB en la pgina www.hobbypic.com
buscar el archivo picusb.zip (all est todo, circuito elctrico, cdigo fuente, etc.).
- all hay un pdf donde aparece el circuito elctrico, para el 18F2550, bueno yo estoy
usando el 18F4550 y sirve tambin. solo hay que cambiar el encabezado por #include
<18F4550.h>
- usar un software para enviar los comandos que activaran los leds, yo an no tengo el
visual C#, pero ya que el amigo Diego RedPic realiz uno que es compatible con el
mismo cdigo, lo us y se llama PicUSBDelphi.exe (forma parte del archivo
PicUSBDelphi.zip que se baja desde la pgina picmania.garcia-
cuervo.net/usb_0_desencadenado.php).

Programa PiCUSB de RedMania
este archivo se encuentra en PicUSBDelphi.zip, y funciona con la librera mpusbapi.dll
que debe estar en el mismo directorio.
- seguido conectar todo. Hay que revisar los contactos del conector USB. Yo us el plug
estndar tipo A (visto de la parte de abajo)
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 48

Conector USB tipo A
cuyos pines van as: (tomado de especificaciones USB2.0 captulo 6 pgina 99)

Disposicin pines conector USB tipo A
donde:


1=Vbus
2=D-
3=D+
4=Gnd


ese plug lo conect a una extensin, por si acaso med la tensin de Bus=5.1 volts.
- ahora si viene la parte de conectar y enchufar al puerto de la PC, y.
el windows me detect un nuevo dispositivo USB, hay que elegir la carpeta donde estn
los controladores que estn en el mismo picusb.zip, son 4 archivitos:

[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 49

picusb.cat
picusb.inf
picusbci.dll
wdmstub.sys


despus el windows hace todo lo que tiene que hacer (configurar dispositivo, etc.)

Propiedades del Dispositivo USB
y listo, se encendi el circuito en el protoboard. parece que la misma alimentacin del
puerto alimenta al circuito
-ahora falta cargar el programa en la PC y hacer las respectivas pruebas:
http://www.youtube.com/watch?v=XZN4L9kimr0
como podrn ver en este ejemplo, aqu no se habla de programacin ni de
funcionamiento, simplemente me lanc a probar ese cdigo y siento especial alegra
porque ya pude hacer mi primera transmisin de datos a un PIC va USB! Gracias a
J1M y RedPic.

[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 50
Usando el Mdulo USB CDC (Parte 1)
Aqu hay otro ejemplito para ir aprendiendo y practicando con el mdulo USB que trae
el 18F4550, esta vez se va a utilizar la clase CDC Communications Devices Class,
entrando un poquito en teora, se puede decir que una clase USB es un grupo de
dispositivos (o interfaces dentro de un dispositivo) con ciertas caractersticas en comn.
Tpicamente, dos dispositivos pertenecen a la misma Clase si ambos utilizan formatos
similares en los datos que reciben o transmiten, o si ambos utilizan una misma forma de
comunicarse con el sistema.
tal es el caso de esta clase que permite a la funcin( dispositivo) comunicarse con el
COM virtual a travs del controlador HOST de USB en la computadora.
nota: este tema sobre la teora y funcionamiento del bus USB no es para digerirlo a la
primera leda, pues tambin hay que estudiarlo al nivel del mdulo que trae el PIC
en este ejemplo (ejemplo6_parte2) le vamos a decir al PIC que envi un mensaje
(string) a la computadora, siempre y cuando el software se lo ordene. El software se va
hacer en visual basic y para ello abrimos el VB y pegamos un control activeX, en el
formulario y es el MSCOMM.ocx

Invocando el control mscomm.ocx en vb
pegamos varios controles hasta que nos queda esta pantalla:
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 51

Programa ejemplo CDC-VB
como vern hay 2 botones cada uno para enviar la orden al PIC y despus ste, nos
envi la respectiva cadena, dicha orden ser un byte un carcter, posteriormente esa
cadena se guardar en la caja de texto.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
' ejemplo6_parte2 comunicacin al PIC mediante el puerto virtual
COM4 cuya transmisin
' real ser por el USB enviando un caracter para confirmarle al PIC,
la transmisin
' de una cadena de acuerdo al caracter enviado
' 12-ene-07
' Pedro - PalitroqueZ
Option Explicit

Private Sub Command1_Click()
If MSComm1.PortOpen = False Then
MSComm1.PortOpen = True
End If
MSComm1.Output = "x"
End Sub

Private Sub Command2_Click()
If MSComm1.PortOpen = False Then
MSComm1.PortOpen = True
End If
MSComm1.Output = "a"
End Sub

Private Sub Form_Load()
MSComm1.CommPort = 4
MSComm1.OutBufferSize = 1 'tamao del dato a transmitir
MSComm1.InBufferSize = 23
MSComm1.InputMode = comInputModeText 'los datos se recuperan en
modo texto


MSComm1.InputLen = 23 ' BUFFER DE ENTRADA SE PUEDE DEJAR AL
MAXIMO
MSComm1.PortOpen = True
MSComm1.RThreshold = 23 'son 23 caracteres "presionaste el
nmero 1"

End Sub

Private Sub Form_Unload(Cancel As Integer)
If MSComm1.PortOpen = True Then
MSComm1.PortOpen = False
End If
End Sub
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 52
45
46
47
48
49
50
51

Private Sub MSComm1_OnComm()
Dim InBuff As String
Select Case MSComm1.CommEvent
Case comEvReceive
InBuff = MSComm1.Input
Debug.Print InBuff
Text1.Text = ""
Text1.Text = Left$(InBuff, 23) ' se recorta los caracteres
basura
MSComm1.PortOpen = False 'cierra el puerto y vacia el buffer
End Select
End Sub
de este cdigo hay varias cosas que decir, lo primordial es tener bien configurado al
MSCOMM, como por ejemplo RThreshold y para evitar caracteres extraos o los
famosos chr(10) y chr(13) recortar la cadena a 23 caracteres como en este caso.
Otra cosa que coloqu fue cerrar el puerto despus de ejecutar el evento comEvReceive,
entre otras cosas para limpiar el buffer, en fin es cuestin de que hagan los respectivos
ensayos de acuerdo a cada situacin.
ahora viene escribir el cdigo para el PIC:
1
2
3
4
5
6
7
8
9
1
0
1
1
1
2
1
3
1
4
1
5
1
6
1
7
1
8
1
9
2
0
2
1
2
/* ejemplo6_parte2.c
este ejemplo hace uso del mdulo USB en modo CDC transmitiendo
datos
hacia un puerto COMx emulado en Windows
adaptacin del cdigo original de RRCdcUSB de RedPic
Pedro-PalitroqueZ
12/01/07
*/
#include <18F4550.h>
#fuses
XTPLL,MCLR,NOWDT,NOPROTECT,NOLVP,NODEBUG,USBDIV,PLL1,CPUDIV1,VREGEN,
NOPBADEN
#use delay(clock=48000000)

#include "usb_cdc.h"

void main() {
usb_cdc_init();
usb_init();
while(!usb_cdc_connected()) {}
// espera a detectar una transmisin de la PC (Set_Line_Coding)
do{
usb_task();
if (usb_enumerated()){
if(usb_cdc_kbhit()){ //en espera de nuevo(s) caracter(es)
en el buffer
if(usb_cdc_getc()=='x'){ //lo que lleg fu el caracter
x?
printf(usb_cdc_putc, "el 11111111111111111111\n\r");
//si, entonces enva una cadena hacia el PC
}
if(usb_cdc_getc()=='a'){ //lo que lleg fu el caracter
a?
printf(usb_cdc_putc, "el 22222222222222222222\n\r");
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 53
2
2
3
2
4
2
5
2
6
2
7
2
8
2
9
3
0
3
1
3
2
3
3
//si, entonces enva una cadena hacia el PC
}
}
}
}while (TRUE); // bucle eterno
}
all se puede apreciar que si el byte que llega es una x, entonces se prepara para
transmitir ese montn de unos, y si llega una a manda ese montn de does
ahora se procede a compilar,grabar el PIC, revisar conexiones, etc. y probar la
transmisin, pero ANTES hay que instalar la aplicacin para la clase CDC, solo hay que
clicar en un archivito llamado mchpcdc.inf .
como en este ejemplo, no se utilizar componentes adicionales, no har falta
alimentacin externa y se puede hacer directamente desde Vusb
http://www.youtube.com/watch?v=uCn2wOmnv2M
observen que si no hay COM4 el VB tira el error porque no encuentra dicho puerto,
pero cuando conectamos el cable todo funciona, bueno ah habra que aplicar una
validacin para saltar ese error usando un On Error GoTo.


Conclusiones:
- con este ejemplo se pretende hacer transmisiones de PIC<->PC usando el puerto USB
real pero mediante el COM virtual
- usando la clase CDC es una manera fcil y rpida de hacer comunicacin con la
computadora, ya que podemos tomar programas de VB ya hechos para el MSCOMM y
que mediante una pequea adaptacin podemos transmitir por el USB. La programacin
para el PIC vara ligeramente.


[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 54
Usando el Mdulo USB CDC (Parte 2)
Seguimos con el mdulo USB y con la clase CDC, porque a mi pensar es una manera
fcil de usar el cable USB sin meterse tanto en las capas de este protocolo, y la verdad
esas librerias que trae el compilador CCS son las que se encargan de todo.
mirando por un momento qu se hizo en el ejemplo anterior?, nos ahorramos el
circuito del MAX232!
en este ejemplo6_parte3 vamos a profundizar la transmisin de datos, se tomar el
cdigo del ejemplo anterior y se estudiar el comportamiento de las funciones


usb_enumerated()
usb_cdc_kbhit()
usb_cdc_getc()
usb_cdc_connected()


recordemos que usb_cdc_connected() detecta si el controlador host est enviando datos
y usb_enumerated() es para que el PC detecte nuestro dispositivo ( funcin), pero eso
no quiere decir que el pic har otras actividades si el cable est enchufado no.
modificando el cdigo de ejemplo anterior
1
2
3
4
5
6
7
8
9
1
0
1
1
1
2
1
3
1
4
1
5
1
6
1
7
1
8
1
9
/* ejemplo6_parte3.c
en este ejemplo se tratar de concocer la configuracin del
dispositivo, cuando
hay/no hay conexin con el PC mediante los comandos
usb_enumerated()
usb_cdc_kbhit()
usb_cdc_getc()
usb_cdc_connected()

adaptacin del cdigo original de RRCdcUSB de RedPic
Pedro-PalitroqueZ 14/01/07
*/
#include <18F4550.h>
#fuses
XTPLL,MCLR,NOWDT,NOPROTECT,NOLVP,NODEBUG,USBDIV,PLL1,CPUDIV1,VREGEN,
NOPBADEN
#use delay(clock=48000000)

#define use_portb_lcd TRUE

#include <lcd.c>
#include "usb_cdc.h"

void main(){
usb_cdc_init(); // llamadas necesarias para iniciar el mdulo USB
usb_init(); // llamadas necesarias para iniciar el mdulo USB
lcd_init(); // llamadas necesarias para iniciar la LCD
while(!usb_cdc_connected()) {lcd_putc("\fUSB NO detectadO");
delay_ms(100);} // para evitarme un retardo y que no parpadee la
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 55
2
0
2
1
2
2
2
3
2
4
2
5
2
6
2
7
2
8
2
9
3
0
3
1
3
2
3
3
3
4
3
5
3
6
3
7
3
8
3
9
4
0
4
1
4
2
4
3
4
4
4
5
LCD
// espera a detectar una transmisin de la PC (Set_Line_Coding)
lcd_putc("\fUSB DeTectAdo"); delay_ms(600);
do{
usb_task();
if (usb_enumerated()){
lcd_putc("\fya enumerado\n"); // para evitarme un retardo
y que no parpadee la LCD
lcd_putc("USB ConeCtaDo"); // para evitarme un retardo y
que no parpadee la LCD
delay_ms(800);
if(usb_cdc_kbhit()){ //en espera de nuevo(s) caracter(es)
en el buffer
if(usb_cdc_getc()=='a'){ //lo que lleg fu el caracter
a?
lcd_putc("\fdAto rEciBido\n"); // para evitarme un
retardo y que no parpadee la LCD
lcd_putc("de la PC"); // para evitarme un retardo y
que no parpadee la LCD
delay_ms(800); //tiene que ser mayor a 500mS para que
no existan parpadeos
}
}
}
lcd_putc("\fEn El bUClE UsB"); // para evitarme un retardo y que
no parpadee la LCD
delay_ms(700);
}while (TRUE); // bucle eterno
}
all inclu una pantalla LCD, el cul me mostrar que sucede en determinado momento
dentro del cdigo, la idea es conocer que hace el pic cuando:
- no hay conexin
- conectado el cable USB
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 56
- ejecutando la aplicacin VB
- enviando el dato hacia el dispositivo
y todo eso me lo mostrar en pantalla con unos lcd_putc que coloqu en lugares
estratgicos, el cdigo en VB lo modifiqu ligeramente, para que enve un carcter y no
reciba ninguno. vamos a grabar el pic y a probar:
http://www.youtube.com/watch?v=iqxsPdhOUUc
estos son los mensajes del LCD y las acciones que llev a cabo:


MENSAJES -> CASOS POSIBLES


- USB no detectado -> el cable USB SI est NO est enchufado al PC
- USB detectado, ya enumerado USB conectado, en el bucle USB -> sucede
cuando ejecuto la aplicacin en VB
- dato recibido de la PC -> sucede cuando clco en el botn enviando a al pic
recomendacin: pegar un switche doble para desconectar a D- D+, para no estar a cada
rato sacando la extensin y hacer una reconexin fcil.
esto est correcto solo en funcin del cdigo, pues una vez que entra dentro del bucle no
sale, y siempre mostrar que est conectado aunque no sea cierto.
si cierro la aplicacin de VB y la vuelvo a abrir har todo OK, porque seguir en el
mismo bucle.
hay una cosa curiosa que sucedi cuando apliqu un reset al PIC, en administrador de
dispositivos reaparece el COM, pero en el programita de VB, se cuelga y no me detecta
jams el puerto a menos que reconecte el cable USB de nuevo, ??
la solucin a este inconveniente se encuentra en el siguiente tpico Monitorear el puerto
COM virtual. Esto se llamara: conexin en caliente del lado del software, (ya est
arreglado en el video).
el cdigo en VB:
1
2
3
4
5
6
7
8
9
10
11
' ejemplo6_parte2 comunicacin al PIC mediante el puerto virtual
COM4 cuya transmisin
' real ser por el USB enviando un caracter para confirmarle al PIC,
la transmisin
' de una cadena de acuerdo al caracter enviado
' 12-ene-07
' Pedro - PalitroqueZ

' el uso de bandera permite averiguar varios datos para confirmar el
estado real
' de la conexin
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 57
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
Option Explicit
Dim value As Long
Dim bandera As Boolean


Private Sub Command2_Click()
Timer1.Enabled = False
If MSComm1.PortOpen = True Then
MSComm1.Output = "a"
End If
Timer1.Enabled = True
End Sub


Private Sub Form_Load()
MSComm1.CommPort = 4
MSComm1.OutBufferSize = 1 'tamao del dato a transmitir

Timer1.Interval = 50
Timer1.Enabled = True
bandera = False
End Sub

Private Sub Form_Unload(Cancel As Integer)
If MSComm1.PortOpen = True Then
MSComm1.PortOpen = False
End If
End Sub

Private Sub Timer1_Timer()
On Error GoTo paca
DoEvents
If MSComm1.PortOpen = True Then
DoEvents
lblestado.Caption = "Conectado"
Debug.Print "Conectado"
MSComm1.PortOpen = False
Exit Sub
Else
DoEvents
MSComm1.PortOpen = True
Exit Sub
End If
paca: Debug.Print Err.Number & ": " & Err.Description
Select Case Err.Number
Case 8002 'Nmero de puerto no vlido
DoEvents
lblestado.Caption = "Desconectado"
Case 8005 'el puerto ya est abierto
DoEvents
lblestado.Caption = "puerto abierto"
Case 8012 '8012 el dispositivo no est abierto
DoEvents
lblestado.Caption = "Desconectado"
Case 8015
DoEvents ' para evitar retardos en bucles
lblestado.Caption = "Desconectado"
End Select
Exit Sub
End Sub
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 58
lecturas recomendadas:
AN956 Migrating Applications to USB from RS-232 UART with Minimal Impact on PC
Software
Emulating RS-232 over USB with PIC18F4550

volver arriba
Monitorear el puerto COM virtual
Prob el estado de una conexin pero solo en el software de la PC, sin enviar datos
(independiente del cdigo que exista en el PIC, el programa ver si existe o no el
COMx). una solucin que encontr fu abrir y cerrar el puerto dentro del escaneo
peridico del control timer.
si logro abrir el puerto es porque existe el COMx, si me genera un error es porque
podra no existir, en cualquiera de los casos en que no pueda abrir el COMx asumo que
est desconectado y no se puede transmitir datos.
ah ocurren 2 cosas distintas:
cuando se intenta abrir el puerto y se deja abierto, no hay manera de saber si el cable se
desconect.
el timer abre y cierra el puerto, si el puerto est cerrado, quiere decir que el COMx no
existe, entonces cuando en el evento timer abra de nuevo el puerto, el VB tirar un error
, especficamente el error 8015: No se puede establecer el estado de comunicacin;
puede que haya uno o ms parmetros de comunicaciones no vlidos 8002: Nmero
de puerto no vlido, es all que mediante el control de errores puedo decir que el pic est
desconectado del controlador HOST de la PC
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Option Explicit

Private Sub Command1_Click()
Timer1.Enabled = False
If MSComm1.PortOpen = False Then
Exit Sub
Else
MSComm1.Output = "a"
End If
Timer1.Enabled = True
End Sub

Private Sub Form_Load()
MSComm1.CommPort = 4
MSComm1.OutBufferSize = 1 'tamao del dato a transmitir
'MSComm1.PortOpen = True

Timer1.Interval = 50
Timer1.Enabled = True
End Sub
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 59
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59

Private Sub Form_Unload(Cancel As Integer)
If MSComm1.PortOpen = True Then
MSComm1.PortOpen = False
End If
End Sub

Private Sub Timer1_Timer()
Dim a As String
On Error GoTo paca
DoEvents
If MSComm1.PortOpen = True Then
DoEvents
lblestado.Caption = "Conectado"
Debug.Print "Conectado"
MSComm1.PortOpen = False
Exit Sub
Else
DoEvents
MSComm1.PortOpen = True
Exit Sub
End If
paca: Debug.Print Err.Number & ": " & Err.Description
Select Case Err.Number
Case 8002 'Nmero de puerto no vlido
DoEvents
lblestado.Caption = "Desconectado"
Case 8005 'el puerto ya est abierto
DoEvents
lblestado.Caption = "puerto abierto"
Case 8012 '8012 el dispositivo no est abierto
DoEvents
lblestado.Caption = "Desconectado"
Case 8015
DoEvents
lblestado.Caption = "Desconectado"
End Select
Exit Sub
End Sub
un videito donde se muestra lo que sucede
http://www.youtube.com/watch?v=KaxdQfxHItQ
si quisiera enviar datos al PIC, lo primero que tengo que hacer es detener el escaneo,
mediante Timer1.Enabled = False y pego un cdigo similar al del evento timer (para
que ocurra solo una vez) dentro del evento donde quiero enviar datos, despus que
envie/reciba datos, arranco el escaneo Timer1.Enabled = True
es decir, mientras no est haciendo operaciones de transmisiones por el USB, el timer
estar encendido y solo se dentendr cuando se realice un envo/recepcin de datos.

[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 60
Detectando el HOST
Despus de varios das de descanso y para poner a trabajar al subconsciente en esto del
USB seguimos con este mdulo, y porqu? es que este mdulo es la joya de la corona
de este PIC, as que seguir echndole mano hasta abarcar todo lo necesario para
realizar una comunicacin PIC<->PC bsica.
ya en el ejemplo anterior dimos cuenta de como detectar una conexin por software,
desde el punto de vista de un programa en la PC, ahora le toca el turno al hardware del
PIC, es decir, que el pic debe detectar al host USB.
hay algo que pas por alto, desde que empec con estos ejemplitos del CDC, hay una
constante:
1
2
3
4
5
6
7
8
#include <18F4550.h>
#fuses
XTPLL,MCLR,NOWDT,NOPROTECT,NOLVP,NODEBUG,USBDIV,PLL1,CPUDIV1,VREGEN,N
OPBADEN
#use delay(clock=48000000)

#include "usb_cdc.h"

void main() {
...
la constante es el llamado al driver usb_cdc.h y no crean que es el nico archivo usado,
si miran dentro de ste vern despus de varias lneas:
1
2
3
4
5
6
7
8
9
10
11
#if __USB_PIC_PERIF__
#if defined(__PCM__)
#error CDC requires bulk mode! PIC16C7x5 does not have bulk mode
#else
#include <pic18_usb.h> //Microchip 18Fxx5x hardware layer for
usb.c
#endif
#else
#include <usbn960x.c> //National 960x hardware layer for usb.c
#endif
#include "rr2_USB_Cdc_Monitor.h" //USB Configuration and Device
descriptors for this UBS device
#include <usb.c> //handles usb setup tokens and get
descriptor reports
como estamos usando el 18F4550 entonces se utilizar el driver pic18_usb.h y adems
el rr2_USB_Cdc_Monitor.h y el usb.c
caramba se usan varias libreras y estas a su vez llaman a otras.
por ejemplo la rr2_USB_Cdc_Monitor.h es la usb_desc_cdc.h que est en la carpeta
driver en PICC, solo que est modificada para identificar nuestro dispositivo como
queramos (esto lo explica el amigo RedPic en su pgina) de la que me interesa hablar es
la librera pic18_usb.h
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 61
si observamos el cdigo del ejemplo anterior hay unas funciones de inicializacin que
hay que llamar para poder empezar a transmitir datos, una de ellas es


usb_init( );


si buscamos que hace esa funcin en pic18_usb.h tenemos:
1
2
3
4
5
6
7
void usb_init(void) {
usb_init_cs();

do {
usb_task();
} while (usb_state != USB_STATE_POWERED);
}
si nos metemos dentro de usb_task():
1
2
3
4
5
6
7
8
9
1
0
1
1
1
2
1
3
1
4
1
5
1
6
1
7
1
8
1
9
2
0
2
1
2
2
2
3
2
4
/*******************************************************************
**********
/* usb_task()
/*
/* Summary: Keeps an eye on the connection sense pin to determine if
we are
/* attached to a USB cable or not. If we are attached to a
USB cable,
/* initialize the USB peripheral if needed. If we are
disconnected
/* from the USB cable, disable the USB peripheral.
/*
/* NOTE: If you are not using a connection sense pin, will
automatically
/* enable the USB peripheral.
/*
/* NOTE: this enables interrupts once the USB peripheral is
ready
/*
/*******************************************************************
**********/
void usb_task(void) {
if (usb_attached()) {
...

analicen lo que dice esta funcin, ah se habla de un tal connection
sense pin que interesante, veamos que hace la funcin
usb_attached():
...
/*******************************************************************
***********
/* usb_attached()
/*
/* Summary: Returns TRUE if the device is attached to a USB cable
/*
/*******************************************************************
**********/
#if USB_CON_SENSE_PIN
#define usb_attached() input(USB_CON_SENSE_PIN)
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 62
2
5
2
6
2
7
2
8
2
9
3
0
3
1
3
2
#else
#define usb_attached() TRUE
#endif
...
uuhmmm esa funcin est hecha mediante definicin y llama a su vez a un tal
USB_CON_SENSE_PIN
haciendo una pausa, esto que estoy haciendo es analizando el cdigo inversamente, es
decir, mediante una simulacin en el MPLAB voy observando donde cae cada llamado
para as determinar esa parte del cdigo que me interesa.
quin es ese USB_CON_SENSE_PIN? y porque en mi simulacin del MPLAB salta
sin preguntar por l?. En la nota de arriba dice que si no se est usando,
automticamente se habilitar el mdulo USB.
http://www.youtube.com/watch?v=Tg_KTJ-8WfE
la lnea BTFSC 0xf6d, 03 est preguntando si USBEN=0, mientras que para el primer
condicional no aparece su respectiva lnea en asm.
ahora que recuerdo en el cdigo que escribi el amigo J1M, aparece una descripcin de
ese USB_CON_SENSE_PIN
(tambin aparece en el ejemplo ex_usb_serial2.c que trae el CCS)
1
2
3
4
5
6
7
8
9
1
0
1
1
1
2
1
3
1
4
////////////////////////////////////////////////////////////////////
/////////
//
// If you are using a USB connection sense pin, define it here. If
you are
// not using connection sense, comment out this line. Without
connection
// sense you will not know if the device gets disconnected.
// (connection sense should look like this:
// 100k
// VBUS-----+----/\/\/\/\/\----- (I/O PIN ON PIC)
// |
// +----/\/\/\/\/\-----GND
// 100k
// (where VBUS is pin1 of the USB connector)
//
////////////////////////////////////////////////////////////////////
/////////
//#define USB_CON_SENSE_PIN PIN_B2 //CCS 18F4550 development kit
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 63
1
5
1
6
has optional conection sense pin
...
y se hace llamar antes que los drivers, quiere decir entonces que hay una forma de
detectar (mediante hardware) cuando el host est conectado al PIC y es al sensar un
voltaje en un pin establecido, especficamente el voltaje del bus USB (VBUS)
vamos a probar pues! usemos el pin RE3 se acuerdan? el del MCLR que solo puede
funcionar como entrada digital.


#define USB_CON_SENSE_PIN PIN_E3 //pin de MCLR
hay una cosa que es digna de hacerle un estudio, me refiero a la funcin usb_task() que
est dentro de usb_init(), si hacen la prueba y se ponen hacer la simulacin con el
MPLAB descubrirn 2 diferencias habilitando/deshabilitando el conection sense pin,
otra cosa importante hablando del ejemplo anterior sabemos que el cdigo se encierra
dentro de un while
1
2
3
4
...
while(!usb_cdc_connected()){
...
}
pero y porque el HOST puede seguir reconociendo a la funcin an dentro de ese
bucle? si miran dentro de usb_task vern este cdigo:
1
2
3
4
5
...
enable_interrupts(INT_USB);
enable_interrupts(GLOBAL);
UIE=__USB_UIF_IDLE | __USB_UIF_RESET; //enable IDLE and RESET
USB interrupt
usb_state=USB_STATE_POWERED;
all se est seleccionado/habilitando la fuente de interrupcin USB y cuando se conecta
la funcin al host, se ejecuta uno de los 2 servicios de interrupcin de rutina (SRI) :


usb_isr_rst() -> para el flag __USB_UIF_RESET
usb_isr_uidle() -> para el flag __USB_UIF_IDLE

esto de alguna manera reconecta a la funcin para que sea reconocida por el HOST. est
interesante esta parte, vamos a ver adonde llegamos.
leyendo en la ayuda del CCS tenemos que:
1
2
3
4
usb_task():
If you use connection sense, and the usb_init_cs() for
initialization, then you must periodically call this function to keep
an eye on the connection sense pin.
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 64
When the PIC is connected to the BUS, this function will then perpare
the USB peripheral. When the PIC is disconnected from the BUS, it
will reset the USB stack and peripheral. Will enable and use the USB
interrupt.
Note: In your application you must define USB_CON_SENSE_PIN to the
connection sense pin.

usando el pin RE3 (no olviden cambiar el fuse a NOMCLR) como sense pin, vamos
hacer unas simulaciones a ver que pasa
http://www.youtube.com/watch?v=7-8jEVfqZC8
noten que ahora si aparecen las lneas en asm que corresponden a if(usb_attached()){.
all est preguntando por el estado de RE3
prosigamos con el MPLAB-SIM, vamos a tener que averiguar que ocurre si hay una
interrupcin
1
2
3
4
5
6
7
8
9
10
11
12
void usb_cdc_init(void) {
usb_cdc_line_coding.dwDTERrate=9600;
usb_cdc_line_coding.bCharFormat=0;
usb_cdc_line_coding.bParityType=0;
usb_cdc_line_coding.bDataBits=8;
(int8)usb_cdc_carrier=0;
usb_cdc_got_set_line_coding=FALSE;
usb_cdc_break=0;
usb_cdc_put_buffer_nextin=0;
usb_cdc_get_buffer_status.got=0;
usb_cdc_put_buffer_free=TRUE;
}
me huele a que en esta llamada se hace una especie de configuracin tipo USART.
despus de activar el estmulo de RE3 caigo en este segmento de cdigo:
1
2
3
4
5
6
7
8
9
...
if ((usb_state == USB_STATE_ATTACHED)&&(!UCON_SE0)) {
UIR=0;
UIE=0;
enable_interrupts(INT_USB);
enable_interrupts(GLOBAL);
UIE=__USB_UIF_IDLE | __USB_UIF_RESET; //enable IDLE and RESET USB
interrupt
usb_state=USB_STATE_POWERED;
debug_usb(debug_putc, "\r\n\nUSB TASK: POWERED");
este cdigo ya lo haba puesto antes, pues bien, despus de un largo rato no pude
simular esa interrupcin.
queda una cosa por averiguar: que esa interrupcin debe ocurrir cuando hay un
detached, es decir, se desconecta el HOST de la funcin, porque digo esto?, porque si
sigo simulando me doy cuenta que llego al bucle main y all caigo en el bucle eterno
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 65
1
2
while(!usb_cdc_connected()) { //bucle eterno
delay_cycles(1);} // para evitarme un retardo y que no parpadee la
LCD
leyendo en el driver pic18_usb.h sobre esta lnea:


UIE=__USB_UIF_IDLE | __USB_UIF_RESET; //enable IDLE and RESET USB
interrupt
tenemos unos defines:


#define __USB_UIF_IDLE 010 -> bit 4
#define __USB_UIF_RESET 001 -> bit 0
si nos vamos a la datasheet del 18F4550, Pg. 180 nos encontramos un SFR llamado
UIR

Registro Estado interrupcin USB
este SFR contiene los flags de los estados de interrupcin seleccionados por UIE
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 66

Registro habilitacin Interrupcin USB
con este par de bits lo que hacemos es seleccionar el par USB Reset Interrupt y Idle
Detect Interrupt Enable bit
otro dato importante, si nos vamos a la descripcin de ambos servicio de interrupcin,
veremos
para el RESET:
1
2
3
4
5
6
7
/********************************************************************
***********
/* usb_isr_rst()
/*
/* Summary: The host (computer) sent us a RESET command. Reset USB
device
/* and token handler code to initial state.
/*
/********************************************************************
************/
para el estado IDLE:
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 67
1
2
3
4
5
6
/********************************************************************
***********
/* usb_isr_uidle()
/*
/* Summary: USB peripheral detected IDLE. Put the USB peripheral to
sleep.
/*
/********************************************************************
************/
nuevamente deduzco lo siguiente:
- que ambos casos sirven para detectar el estado HOST<->PIC.
como lamentablemente no puedo hacer la simulacin, no me queda de otra que probar el
cdigo en el protoboard, pero haciendo unas modificaciones, el cdigo quedar as:
1
2
3
4
5
6
7
8
9
1
0
1
1
1
2
1
3
1
4
1
5
1
6
1
7
1
8
1
9
2
0
2
1
2
2
2
3
2
4
2
5
2
6
2
/* ejemplo6_parte4_temp.c
en este ejemplo se tratar se ordenar al PIC reconocer la
deteccin del HOST USB de la PC

adaptacin del cdigo original de RRCdcUSB de RedPic
Pedro-PalitroqueZ 4/feb/07
*/
#include <18F4550.h>
#fuses
XTPLL,NOMCLR,NOWDT,NOPROTECT,NOLVP,NODEBUG,USBDIV,PLL1,CPUDIV1,VREGE
N,NOPBADEN
#use delay(clock=48000000)

#define use_portb_lcd TRUE

#define USB_CON_SENSE_PIN PIN_E3
#include <lcd.c>
#include "usb_cdc.h"

void main(){
lcd_init(); // llamadas necesarias para iniciar la LCD
usb_cdc_init(); // llamadas necesarias para iniciar el mdulo USB
usb_init(); // llamadas necesarias para iniciar el mdulo USB
while(!usb_cdc_connected()) { //bucle eterno
delay_us(500);
}
do{
usb_task();
delay_us(500);
}while (TRUE); // bucle eterno
}
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 68
7
2
8
y en el driver pic18_usb.h coloqu un par de lneas nuevas:
1
2
3
4
5
6
7
8
9
10
11
12
void usb_attach(void) {
usb_token_reset();
lcd_putc("\fUSB CONECTADO");
delay_ms(100);
...
}

void usb_detach(void) { //done
lcd_putc("\fUSB DESCONECTADO");
delay_ms(100);
...
}
despus de revisar bien las conexiones, el .lst para ver si estn OK los fuses, se procede
a grabar el PIC y a ensayar:
con el HOST:

USB conectado en LCD
sin el HOST:
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 69

USB Desconectado en LCD
arrg! que mala pata, se queda activado el USB CONECTADO an despus de
desconectar al HOST
obviamente hay que revisar nuevamente a pic18_usb.h
vamos a repasar, segn mi hiptesis para que el mdulo USB arranque la funcin
usb_task() debe esperar por el nivel alto en RE3 (proveniente de Vusb) y si ocurre
selecciona/habilita la interrupcin para los casos USB Reset e Idle Detect hasta aqu
vamos bien, ahora que debe ocurrir para que ocurra una de esas 2 interrupciones?
primero que nada si ocurre una interrupcin el contador de programa se v para:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#int_usb
void usb_isr() {
if (usb_state==USB_STATE_DETACHED) return; //should never
happen, though
if (UIR) {
debug_usb(debug_putc,"\r\n\n[%X] ",UIR);
if (UIR_ACTV && UIE_ACTV) {usb_isr_activity();} //activity
detected. (only enable after sleep)

if (UCON_SUSPND) return;

if (UIR_UERR && UIE_UERR) {usb_isr_uerr();} //error
has been detected

if (UIR_URST && UIE_URST) {usb_isr_rst();} //usb reset
has been detected

if (UIR_IDLE && UIE_IDLE) {usb_isr_uidle();} //idle
time, we can go to sleep
if (UIR_SOF && UIE_SOF) {usb_isr_sof();}
if (UIR_STALL && UIE_STALL) {usb_isr_stall();} //a
stall handshake was sent

[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 70
if (UIR_TRN && UIE_TRN) {
usb_isr_tok_dne();
UIR_TRN=0; // clear the token done interrupt., 0x190.3
} //a token has been detected (majority of isrs)
}
}
ah est otra vez el debug_usb(), me intriga saber como se usa??. esa lnea es crucial
porque se puede averiguar quien demonios fue el flag que se activ. voy a ser prctico,
sustituir a debug_usb por printf as:


printf(lcd_putc,\f UIR= %X,UIR);
delay_ms(500);
sin conectar el HOST: USB CONECTADO


[1]conectando al HOST: UIR= 10 y luego cambia a 01
[2]desconectando el HOST: UIR=54 y luego cambia a 44


y para rematar al poco tiempo me sale un mensaje del windows diciendo que no
reconoce al dispositivo.


54-> 01010100
44-> 01000100
[1]: el flag correcto es USB reset
[2]: los flags involucrados son: start of frame, idle detect y bus activity


seores, esto se complic! lo mejor es entrarle por otro lado, la experiencia que he
tenido me dice que cuando algo se complica, es que por ah no es la solucin.
mirando por ensima vez el cdigo principal veo que aparte de que hacen la llamada
usb_task() dentro de usb_init() la hacen afuera , es decir, se puede usar estas funciones
dentro de nuestro cdigo como queramos.
esta usb_init es importante porque habilita o no el mdulo USB, y que tal si usamos
esa funcin en vez de meternos con el driver?
para ello tendremos que quitar la lnea:


while(!usb_cdc_connected()) { //bucle eterno
eso no nos importa por ahora, yo no voy a enviar datos al pic, lo nico que quiero es
que el pic me diga si o no!
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 71
vamos a intentar ooootra vez:
1
2
3
4
5
6
7
8
9
1
0
1
1
1
2
1
3
1
4
1
5
1
6
1
7
1
8
1
9
2
0
2
1
2
2
2
3
2
4
2
5
/* ejemplo6_parte4_temp.c
en este ejemplo se tratar se ordenar al PIC reconocer la
deteccin del HOST USB de la PC

adaptacin del cdigo original de RRCdcUSB de RedPic
Pedro-PalitroqueZ 4/feb/07
*/
#include <18F4550.h>
#fuses
XTPLL,NOMCLR,NOWDT,NOPROTECT,NOLVP,NODEBUG,USBDIV,PLL1,CPUDIV1,VREGE
N,NOPBADEN
#use delay(clock=48000000)

#define use_portb_lcd TRUE

#define USB_CON_SENSE_PIN PIN_E3
#include <lcd.c>
#include "usb_cdc.h"

void main(){
lcd_init(); // llamadas necesarias para iniciar la LCD
usb_cdc_init(); // llamadas necesarias para iniciar el mdulo USB
usb_init(); // llamadas necesarias para iniciar el mdulo
USB
do{
usb_task();
delay_us(500);
}while (TRUE); // bucle eterno
}

http://www.youtube.com/watch?v=nHt3RWJeoT4
en el video anterior quit lo relacionado a la pantalla LCD para resaltar la parte importante,
pero al grabar el PIC se las puse de nuevo:
http://www.youtube.com/watch?v=Ht2T5T7v8Ao

[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 72
ahora si funcion, aunque fuera por poleo (no veo ninguna interrupcin aqu) pero algo
es algo, ya sabemos que: con la funcin usb_task() podemos determinar el estado de
conexin.
observacin: el error que me apareci en el windows al no detectar el dispositivo en
cierto tiempo se debi al retardo de 500mS que met en #int USB
seguro alguien preguntar: bueno pero si no habilito el sense pin har lo mismo?. y yo
le responder que no, puesto que con esa deshabilitacin, el mdulo USB siempre estar
encendido. (comprobado)
el problema no termina aqu, la idea principal es escribir un cdigo donde se muestre el
estado y que aparte realice otras actividades.

[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 73
Detectando el Host (Continuacin)
Quera continuar con un ejemplo prctico (de hecho ya lo comenc), pero hay unos
detalles que vale la pena mencionar.
segn el anlisis anterior, se dijo que la llamada usb_task() era fundamental, porque a
travs de attach() y detach() podamos hacer las reconexiones, pues bien, esto es muy
cierto, pero hay ms, busquemos en la ayuda de CCS varios conceptos:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
usb_init():
Initializes the USB hardware. Will then wait in an infinite loop
for the USB peripheral to be connected to bus (but that doesn't
mean it has been enumerated by the PC). Will enable and use the USB
interrupt.

usb_init_cs():
The same as usb_init(), but does not wait for the device to be
connected to the bus. This is useful if your device is not bus
powered and can operate without a USB connection.

usb_task():
If you use connection sense, and the usb_init_cs() for
initialization, then you must periodically call this function to
keep an eye on the connection sense pin.

When the PIC is connected to the BUS, this function will then
perpare the USB peripheral. When the PIC is disconnected from the
BUS, it will reset the USB stack and peripheral. Will enable and
use the USB interrupt.

Note: In your application you must define USB_CON_SENSE_PIN to the
connection sense pin.

usb_detach():
Removes the PIC from the bus. Will be called automatically by
usb_task() if connection is lost, but can be called manually by the
user.

usb_attach():
Attaches the PIC to the bus. Will be called automatically by
usb_task() if connection is made, but can be called manually by the
user.

usb_attached():
If using connection sense pin (USB_CON_SENSE_PIN), returns TRUE if
that pin is high. Else will always return TRUE.

usb_enumerated():
Returns TRUE if the device has been enumerated by the PC. If the
device has been enumerated by the PC, that means it is in normal
operation mode and you can send/receive packets.
noten la diferencia de usb_init() con usb_init_cs(), si queremos ejecutar otros procesos
en el micro usb_init() no nos servira, porque se quedara en un bucle esperando al
HOST (COMPROBADO), y esto no es lo que se quiere, entonces se usar la otra
funcin.
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 74
Esta otra llamada usb_init_cs() va de la mano con usb_task(), porque una vez detectada
Vbus a travs de USB_CON_SENSE_PIN, en task se procede a conectar el bus.
lo principal aqu es estar monitoreando continuamente a USB_CON_SENSE_PIN, ya
sea a travs de usb_attached() de usb_task().
hay otra llamada adicional (aqu se llama a un gento) y es usb_enumerated(), en el
concepto dice que su resultado es un boolean y depender de lo que diga el HOST
1
2
usb_enumerated(): // proviene de USB.C
returns TRUE if device has been enumerated (configured) by host,
FALSE if it has not Do not try to use the USB peripheral until you
are enumerated.
es cierto porque si quiero hacer transaccin de datos con la PC, ambos tienen que estar
de acuerdo.
nota: hay que entender bien porque estn estas funciones y porque se deben ejecutar.
bueno, ya entendido estos conceptos, vamos hacer otro ejemplo. Recuerden: el PIC debe
ejecutar otros procesos independientemente si est o no est el HOST.
1
2
3
4
5
6
7
8
9
1
0
1
1
1
2
1
3
1
4
1
5
1
6
1
7
1
8
1
9
2
0
2
1
2
/* probando_USB.c
es una modificacin del ejemplo6_parte4, aqu se usa una bandera
global
que determinar el estado de conexin del USB, mediante las
llamadas
usb_attach y usb_detach en pic18_usb.h

Modificacin del cdigo original de RRCdcUSB de RedPic
Pedro-PalitroqueZ 11-feb-07
*/
#include <18F4550.h>
#fuses
XTPLL,NOMCLR,NOWDT,NOPROTECT,NOLVP,NODEBUG,USBDIV,PLL1,CPUDIV1,VREGE
N,NOPBADEN
#use delay(clock=48000000)

#define use_portb_lcd TRUE
short estado_usb; // boolean global, se debe declarar antes de
llamar a usb_cdc.h
#define USB_CON_SENSE_PIN PIN_E3
#include <lcd.c>
#include "usb_cdc.h"

void mostrar_estado_usb(short bandera);

void main(){
estado_usb=false;
usb_cdc_init(); // llamadas necesarias para iniciar el mdulo USB
usb_init_cs(); // inicia el USB y sale. va a la par con
usb_task()
lcd_init(); // llamadas necesarias para iniciar la LCD
while(true){
usb_task(); // configura el USB
mostrar_estado_usb(estado_usb);
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 75
2
2
3
2
4
2
5
2
6
2
7
2
8
2
9
3
0
3
1
3
2
3
3
3
4
3
5
3
6
3
7
3
8
3
9
4
0
4
1
4
2
4
3
4
4
4
5
4
6
4
7
4
8
4
9
5
0
5
1
5
2
if(usb_cdc_connected()){
// espera a detectar una transmisin de la PC (Set_Line_Coding)
if (usb_enumerated()){ // aqu se hace el acceso HOST<->PC y
despus sale
if(usb_cdc_kbhit()){ //en espera de nuevo(s) caracter(es)
en el buffer
if(usb_cdc_getc()=='a'){ //lo que lleg fu el
caracter a?

printf(usb_cdc_putc, "Lleg la letra a\n\r"); //
envia una respuesta al HOST --FALTABA ESTA LNEA--

lcd_gotoxy(1,1);
lcd_putc("llego una a ");
delay_ms(500);
}
}
}
}
//*************** aqu se ejecutan otros
procesos*********************//
lcd_gotoxy(1,1);
lcd_putc("otros procesos");
delay_ms(500);
}
}
/************************************************
// esta llamada imprime en la LCD los estados de conectado
// y desconectado del USB dependiendo de la bandera
// estado_usb
//***********************************************/
void mostrar_estado_usb(short bandera){
lcd_gotoxy(10,2);
if(bandera){
lcd_putc(" USB:On");
}else{
lcd_putc("USB:Off");
}
delay_ms(500);
}
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 76
5
3
5
4
5
5
5
6
5
7
5
8
5
9
6
0
6
1
6
2
6
3
para el programa en PC, se utilizar una mezcla del ejemplo6_parte(2,3).
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
' ejemplo6_parte5 comunicacin al PIC mediante el puerto virtual
COM4 cuya transmisin
' real ser por el USB enviando un caracter para confirmarle al
PIC, la transmisin
' de una cadena de acuerdo al caracter enviado
' 12-feb-07
' Pedro - PalitroqueZ

' el uso de bandera permite averiguar varios datos para confirmar
el estado real
' de la conexin
Option Explicit
Dim value As Long
Dim bandera As Boolean


Private Sub Command1_Click()
If MSComm1.PortOpen = True Then
MSComm1.PortOpen = False
End If
End
End Sub

Private Sub Command2_Click()
Timer1.Enabled = False
If MSComm1.PortOpen = True Then
MSComm1.Output = "a"
End If
Timer1.Enabled = True
End Sub


Private Sub Form_Load()
MSComm1.CommPort = 4
MSComm1.OutBufferSize = 1 'tamao del dato a transmitir
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 77
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
MSComm1.InBufferSize = 16 '16 caracteres
'MSComm1.PortOpen = True

MSComm1.InputLen = 16 ' BUFFER DE ENTRADA SE PUEDE DEJAR AL
MAXIMO
MSComm1.RThreshold = 16 '

Timer1.Interval = 10
Timer1.Enabled = True
bandera = False
End Sub

Private Sub Form_Unload(Cancel As Integer)
If MSComm1.PortOpen = True Then
MSComm1.PortOpen = False
End If
End Sub


Private Sub MSComm1_OnComm()
Dim InBuff As String
Select Case MSComm1.CommEvent
Case comEvReceive
InBuff = MSComm1.Input
Debug.Print InBuff
Text1.Text = ""
Text1.Text = Left$(InBuff, 16) ' se recorta los caracteres
basura
MSComm1.PortOpen = False 'cierra el puerto y vacia el buffer
Espera 2 ' retardo de 2 segundos
Text1.Text = ""
End Select
End Sub

Private Sub Timer1_Timer()
On Error GoTo paca
DoEvents
If MSComm1.PortOpen = True Then
DoEvents
lblestado.Caption = "Conectado"
Debug.Print "Conectado"
MSComm1.PortOpen = False
Exit Sub
Else
DoEvents
MSComm1.PortOpen = True
Exit Sub
End If
paca: Debug.Print Err.Number & ": " & Err.Description
Select Case Err.Number
Case 8002 'Nmero de puerto no vlido
DoEvents
lblestado.Caption = "Desconectado"
Case 8005 'el puerto ya est abierto
DoEvents
lblestado.Caption = "puerto abierto"
Case 8012 '8012 el dispositivo no est abierto
DoEvents
lblestado.Caption = "Desconectado"
Case 8015
DoEvents ' para evitar retardos en bucles
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 78
97
98
99
100
101
102
103
104
105
106
107
108
109
110
lblestado.Caption = "Desconectado"
End Select
Exit Sub
End Sub

' procedimiento de retardo
'este cdigo NO es de mi autora, lo baj del internet.
Sub Espera(Segundos As Single)
Dim ComienzoSeg As Single
Dim FinSeg As Single
ComienzoSeg = Timer
FinSeg = ComienzoSeg + Segundos
Do While FinSeg > Timer
DoEvents
If ComienzoSeg > Timer Then
FinSeg = FinSeg - 24 * 60 * 60
End If
Loop
End Sub
ahora compilemos, grabemos, montemos y probemos:
http://www.youtube.com/watch?v=MIedPEPqFio
a verdad que este ejemplo est bastante completo, se puede decir que logramos el
objetivo, a pesar que en el video se observa cierta retraso en la respuesta y esto es
debido a los retardos que introduc tanto en cdigo del PIC, como en VB para que
pudiera observar la ejecucin un poco mas lenta, se cumplen todos los casos (en los
ensayos que hice)


casos:
funcin conectada/desconectada al HOST:
el programa en VB funciona OK (ya lo habamos comprobado en el ejemplo6_parte3)
programa en VB:
- de parte del micro, detecta al HOST y lo muestra en pantalla LCD, y ejecuta la
transmisin HOST->PC, aparte que continua ejecutando otros procesos, y todo ello
independiente del mdulo USB!
Aplicacin Prctica usando la clase CDC
Ahora si!, vamos con una aplicacin. Este ejemplo har los siguiente:
- se utilizar el CAD.
- el resultado del CAD se mostrar en una LCD y se enviaran a la computadora por
USB.
- si no hay conexin, entonces los datos se mostraran solo en la LCD.
- para ambos casos se indicar en la LCD el estado de conexin.
- se aplicar un mini-protocolo a la transmisin, cuando el software en la PC est listo
enviar un carcter al PIC y ste deber recibir dicho carcter para enviar el dato
correspondiente a la PC (una especie de ACK).
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 79
- el resultado del CAD se mostrar en un pantalla LCD de 2 modos, justificacin a la
izquierda a la derecha, dependiendo del cambio de un switche.
pero vamos por partes, primero hay que construir el cdigo del CAD y la LCD, es decir,
sin involucrar al USB. Para ello emplearemos al proteus (esto es para agilizar el proceso
de depuracin y simulacin) y usaremos un pic similar al 18F4550, me refiero al
18F4525.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#include <18f4525.h> //archivo de cabecera

#DEVICE ADC=10 // cad a 10 bits, justificacin a a la derecha
#fuses XT,NOWDT,NOPROTECT,NOLVP,NODEBUG // el fuse que configuramos
anteriormente
#use delay(clock=4000000) // el clock que tendremos a la entrada del
CPU

#define use_portb_lcd TRUE
#include <LCD.c>
#define DERECHA 0
#define IZQUIERDA 1

long value;
void config_adcon2(short justificacion);

void main(){
int i;
OUTPUT_A(0); // todos salidas
OUTPUT_B(0);
OUTPUT_C(0);
OUTPUT_D(0);
OUTPUT_E(0);
lcd_init(); // inicia la LCD
set_tris_a(0x3); // ra0=entradas, los demas=salida
set_tris_b(0x0);
set_tris_c(0x0);
set_tris_d(0x0);
set_tris_e(0x0);
setup_adc_ports( AN0 || VSS_VDD ); // canal AN0, Vref+ = Vdd,
Vref- = Vss
config_adcon2(DERECHA);
lcd_putc("\f"); // para evitarme un retardo y que no parpadee la
LCD
while(1){ // bucle infinito
value = read_adc();
if(input_state(PIN_A1)){ //pregunta por el switche
config_adcon2(DERECHA);
}else{
config_adcon2(IZQUIERDA);
}
for(i=0;i<16;i++){
lcd_gotoxy(16-i,1);
lcd_putc((char)(bit_test(value,i)+0x30));
}
printf(lcd_putc,"\n0x%Lx",value);
}
}
//------------------------------------------------------------------
-----------------------
// cumple la funcin de configurar el bit ADFM para hacer
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 80
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
// la justificacin, tambin se incluye el retardo por hardware de
Tacq
// datos de entrada: bandera de justificacin
// datos de salida: nada
//------------------------------------------------------------------
-----------------------
void config_adcon2(short justificacion){
setup_adc(ADC_CLOCK_DIV_64 ); // reloj de conversin = Fosc / 64
if(justificacion){
#asm
bsf 0xFC0,7 // ADFM <- 1
#endasm
}
else{
#asm
bcf 0xFC0,7 // ADFM <- 0
#endasm
}
#asm // configura Tacq = 2Tad
bsf 0xFC0,3
bcf 0xFC0,4
bcf 0xFC0,5
#endasm
set_adc_channel(0);
}
simulamos el cdigo a ver que tal:
http://www.youtube.com/watch?v=f4igDMssuJ8
cambiamos el cdigo para usarlo en el 18F4550:
1
2
3
4
5
6
7
8
9
#include <18f4550.h> //archivo de cabecera

#DEVICE ADC=10 // cad a 10 bits, justificacin a a la derecha
#fuses
XTPLL,NOMCLR,NOWDT,NOPROTECT,NOLVP,NODEBUG,USBDIV,PLL1,CPUDIV1,NOVREG
EN,NOPBADEN
#use delay(clock=48000000)

// el resto queda igual
...
...
otro video:
http://www.youtube.com/watch?v=5Bbe_kR7sFA
notas:
la directiva #DEVICE ADC=16 realiza la justificacin a la izquierda, no la usar en este
ejemplo, porque solamente se puede usar una vez (el compilador te lo dir).
ya sabemos que el cdigo funciona perfectamente, no tenemos que preocuparnos por
esa parte, ahora tenemos que concatenar la seccin de la transmisin USB
tomando del ejemplo anterior, nuestro cdigo quedara as:
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 81
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
/* aplicacin al ejemplo6_parte5, el resultado del CAD se enviar a
una LCD
y al mismo tiempo (si hay conexin) al PC, mostrando el estado
del USB.
se ha incluido una bandera en la librera pic18_usb.h de manera
de saber
cuando ocurre la llamada attach y detach
parte de este cdigo corresponde al original de RRCdcUSB de
RedPic
Pedro-PalitroqueZ 13-feb-07
*/

#include <18F4550.h>
#DEVICE ADC=10 // cad a 10 bits, justificacin a a la derecha
#fuses
XTPLL,NOMCLR,NOWDT,NOPROTECT,NOLVP,NODEBUG,USBDIV,PLL1,CPUDIV1,VREGE
N,NOPBADEN
#use delay(clock=48000000)

#define use_portb_lcd TRUE
#define USB_CON_SENSE_PIN PIN_E3
#define DERECHA 0
#define IZQUIERDA 1

short estado_usb; // boolean global, se debe declarar antes de
llamar a usb_cdc.h

#include <lcd.c>
#include "usb_cdc.h"

long value;
void config_adcon2(short justificacion);
void mostrar_estado_usb(short bandera);

void main(){
int i;
set_tris_a(0x3); // ra[1,0]=entradas, los demas=salida
estado_usb=false;
usb_cdc_init(); // llamadas necesarias para iniciar el mdulo USB
usb_init_cs(); // inicia el USB y sale. va a la par con
usb_task()
lcd_init(); // llamadas necesarias para iniciar la LCD
setup_adc_ports( AN0 || VSS_VDD ); // canal AN0, Vref+ = Vdd,
Vref- = Vss
config_adcon2(DERECHA);

while(true){
usb_task(); // configura el USB
mostrar_estado_usb(estado_usb);
value = read_adc();
if(input_state(PIN_A1)){ //pregunta por el switche
config_adcon2(DERECHA);
}else{
config_adcon2(IZQUIERDA);
}
for(i=0;i<16;i++){
lcd_gotoxy(16-i,1);
lcd_putc((char)(bit_test(value,i)+0x30));
}
printf(lcd_putc,"\n0x%Lx",value);

[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 82
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
10
0
10
1
10
2
10
3
if(usb_cdc_connected()){
// espera a detectar una transmisin de la PC (Set_Line_Coding)
if (usb_enumerated()){ // aqu se hace el acceso HOST<->PC y
despus sale
if(usb_cdc_kbhit()){ //en espera de nuevo(s) caracter(es)
en el buffer
if(usb_cdc_getc()=='a'){ //lo que lleg fu el
caracter a?
printf(usb_cdc_putc,"%Lx", value); // envia el
ADRESH:ADRESL al HOST
}
}
}
}
}
}
/************************************************
// esta llamada imprime en la LCD los estados de conectado
// y desconectado del USB dependiendo de la bandera
// estado_usb
//***********************************************/
void mostrar_estado_usb(short bandera){
lcd_gotoxy(10,2);
if(bandera){
lcd_putc(" USB:On");
}else{
lcd_putc("USB:Off");
}
//delay_ms(500);
}
//------------------------------------------------------------------
-----------------------
// cumple la funcin de configurar el bit ADFM para hacer
// la justificacin, tambin se incluye el retardo por hardware de
Tacq
// datos de entrada: bandera de justificacin
// datos de salida: nada
//------------------------------------------------------------------
-----------------------
void config_adcon2(short justificacion){
setup_adc(ADC_CLOCK_DIV_64 ); // reloj de conversin = Fosc / 64
if(justificacion){
#asm
bsf 0xFC0,7 // ADFM <- 1
#endasm
}
else{
#asm
bcf 0xFC0,7 // ADFM <- 0
#endasm
}
#asm // configura Tacq = 2Tad
bsf 0xFC0,3
bcf 0xFC0,4
bcf 0xFC0,5
#endasm
set_adc_channel(0);
}
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 83
hay otro detalle que nunca he mencionado, a que velocidad transmite esto? cuando se
ejecuta la funcin usb_cdc_init() aparece:
1
2
3
4
usb_cdc_line_coding.dwDTERrate=9600;
usb_cdc_line_coding.bCharFormat=0;
usb_cdc_line_coding.bParityType=0;
usb_cdc_line_coding.bDataBits=8;
esto forma parte de una estructura en la que sera 9600 bits/sec, 1 bit de parada, sin
paridad, 1 byte de datos. Esto es conocido por el MSCOMM: 9600,n,8,1
hasta este punto lo que resta es checar bien el programa compilar, grabar, y probar
http://www.youtube.com/watch?v=97l6IcbL5EE
en el video anterior us el Siow que trae el CCS, bien ya comprobamos que el pic est
haciendo correctamente todo lo que tiene que hacer.
ahora hay que hacer el programa en VB para darle un toque de elegancia a los datos
obtenidos:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
' ejemplo6_parte2 comunicacin al PIC mediante el puerto virtual
COM4 cuya transmisin
' real ser por el USB enviando un caracter para confirmarle al
PIC, la transmisin
' del resultado del CAD
' 13-feb-07 Pedro - PalitroqueZ
Option Explicit
Dim value As Long
Const color_verde = &HFF00&
Const color_rojo = &HFF&
Dim bandera As Boolean


Function cambiar(valor As Long)
Dim t As Integer: Dim asa As String: Dim pepe As String
pepe = HEXA_BIN(CStr(Hex(valor)))
'Debug.Print "pepe= " & Len(pepe)
'MsgBox pepe
For t = 1 To 16
' Debug.Print pepe
asa = Mid$(pepe, t, 1)
' Debug.Print asa
Label1(t - 1).Caption = asa ' es t-1 porque la matriz cuenta
desde 0
Next t

End Function

Private Sub Check1_Click()
On Error GoTo palla
DoEvents
If Check1.value = 1 Then
DoEvents
Timer1.Enabled = False
Check1.ForeColor = &H8000&
Check1.Caption = "Recibiendo datos..."
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 84
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
If MSComm1.PortOpen = True Then
Timer2.Enabled = True
End If
Timer1.Enabled = True
Else
DoEvents
Timer2.Enabled = False
Check1.value = 0
cambiar (0) '
separar (0) ' limpia los caracteres del display
Check1.ForeColor = color_rojo
Check1.Caption = "Nada que recibir"
Timer1.Enabled = True
End If
Exit Sub
palla:
DoEvents
' Check1.value = 0
'Check1.ForeColor = color_rojo
'Check1.Caption = "Nada que recibir"
Timer2.Enabled = False
Timer1.Enabled = True
Exit Sub
End Sub


Function separar(valor1 As Long)
Dim i As Integer: Dim cadena As String
cadena = CStr(Hex(valor1))
Select Case Len(cadena) ' casos para que se mantenga el numero en
LSB
Case 3: cadena = "0" & cadena
Case 2: cadena = "00" & cadena
Case 1: cadena = "000" & cadena
End Select

For i = 1 To 4
lblhex(i - 1).Caption = Mid$(cadena, i, 1)
Next i
End Function

Private Sub Command1_Click()
Unload Me
End Sub

Private Sub Form_Load()
Dim i As Integer: Dim adres As String
For i = 0 To 15
Label1(i).Alignment = 2
Label1(i).Font.Size = 14
Label1(i).Font.Bold = True
Label1(i).ForeColor = 0
Next i
For i = 0 To 3
lblhex(i).Alignment = 2
lblhex(i).Font.Size = 14
lblhex(i).Font.Bold = True
lblhex(i).ForeColor = 0
Next i
Check1.value = 0
Check1.ForeColor = color_rojo
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 85
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
Check1.Caption = "Nada que recibir"
shpestadousb.FillColor = color_rojo

'adres = "&H" & "3ff" & "&"
'value = Val(adres)

cambiar (0) '
separar (0) '


MSComm1.CommPort = 4
MSComm1.OutBufferSize = 1 'tamao del dato a transmitir
MSComm1.InBufferSize = 4
'MSComm1.InputMode = comInputModeText 'los datos se recuperan
en modo texto


MSComm1.InputLen = 4 ' BUFFER DE ENTRADA SE PUEDE DEJAR AL
MAXIMO
' MSComm1.PortOpen = True
MSComm1.RThreshold = 4 'son 4 caracteres el par ADRESH:ADRESL
Timer1.Interval = 10
Timer1.Enabled = True

Timer2.Interval = 100
Timer2.Enabled = False

End Sub

Private Sub Form_Unload(Cancel As Integer)
If MSComm1.PortOpen = True Then
MSComm1.PortOpen = False
End If
End Sub

Private Sub MSComm1_OnComm()
Dim InBuff As String
Select Case MSComm1.CommEvent
Case comEvReceive
InBuff = MSComm1.Input
Debug.Print "dato llegada: " & InBuff
cambiar (Val("&H" & Left$(InBuff, 4) & "&")) '
separar (Val("&H" & Left$(InBuff, 4) & "&")) '
'MSComm1.PortOpen = False 'cierra el puerto y vacia el buffer
End Select
End Sub

Private Function HEXA_BIN(hexadecimal As String) As String
Dim numero_hexa As String, resultado As String, i As Long,
cadena As String
resultado = ""
'Debug.Print "hexadecimal= " & Len(hexadecimal)
Select Case Len(hexadecimal) ' casos para que se mantenga el
numero en LSB
Case 3: hexadecimal = "0" & hexadecimal
Case 2: hexadecimal = "00" & hexadecimal
Case 1: hexadecimal = "000" & hexadecimal
End Select
For i = 1 To Len(hexadecimal)
numero_hexa = Mid(hexadecimal, i, 1)
Select Case numero_hexa
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 86
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
Case "0"
cadena = "0000"
Case "1"
cadena = "0001"
Case "2"
cadena = "0010"
Case "3"
cadena = "0011"
Case "4"
cadena = "0100"
Case "5"
cadena = "0101"
Case "6"
cadena = "0110"
Case "7"
cadena = "0111"
Case "8"
cadena = "1000"
Case "9"
cadena = "1001"
Case "A"
cadena = "1010"
Case "B"
cadena = "1011"
Case "C"
cadena = "1100"
Case "D"
cadena = "1101"
Case "E"
cadena = "1110"
Case "F"
cadena = "1111"
End Select
resultado = resultado & cadena
'Debug.Print resultado
numero_hexa = ""
Next i
HEXA_BIN = resultado
End Function

Private Sub Timer1_Timer()
On Error GoTo paca
DoEvents
If MSComm1.PortOpen = True Then
DoEvents
shpestadousb.FillColor = color_verde
'lblestado.Caption = "Conectado"
Debug.Print "Conectado"
'MSComm1.Output = "a"
MSComm1.PortOpen = False
Exit Sub
Else
DoEvents
MSComm1.PortOpen = True
Exit Sub
End If
paca: Debug.Print Err.Number & ": " & Err.Description
Select Case Err.Number
Case 8002 'Nmero de puerto no vlido
DoEvents
shpestadousb.FillColor = color_rojo
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 87
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
'lblestado.Caption = "Desconectado"
Case 8005 'el puerto ya est abierto
DoEvents
shpestadousb.FillColor = color_rojo
' lblestado.Caption = "puerto abierto"
Case 8012 '8012 el dispositivo no est abierto
DoEvents
shpestadousb.FillColor = color_rojo
'lblestado.Caption = "Desconectado"
Case 8015
DoEvents ' para evitar retardos en bucles
shpestadousb.FillColor = color_rojo
'lblestado.Caption = "Desconectado"
Case 8018
DoEvents
shpestadousb.FillColor = color_rojo
End Select
cambiar (0) '
separar (0) '
Check1.value = 0

Exit Sub
End Sub

Private Sub Timer2_Timer()
On Error GoTo palla1
MSComm1.Output = "a"
Exit Sub
palla1:
'Timer2.Enabled = False
'Check1.value = 0
Timer1.Enabled = True
Exit Sub
End Sub
el programa tiene un aspecto as:

PiC USB CDC CAD
un par de videos de los resultados prcticos en el protoboard:


Recibiendo datos del ADC:
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 88
http://www.youtube.com/watch?v=2bs91BHRnBg
Desconectando el cable USB:
http://www.youtube.com/watch?v=rW97fDZA0l0
observaciones y conclusiones:
- Este ejemplo demostr una transmisin HOST<->PIC permitiendo al PIC hacer una
actividad aparte.
- se us 2 timer en vez de uno, debido a que en ambos se trabaja en intervalos de
tiempos distintos.
- el conector USB de mi PC ya est algo agrandado de tanto reconectar, esperemos que
aguante un poco mas.
- hay una bandera que yo us llamada:
short estado_usb; // boolean global, se debe declarar antes de llamar a usb_cdc.h
este flag debe ser declarado antes de usb_cdc.h porque hay una funcin all que hace
uso de ella y sirve para mostrar los estados de: USB -> conectado/desconectado.
Especficamente dentro de usb_attach() y usb_detach().
- en el ltimo ejemplo, us 2 videos en vez de uno. porque el camtasia studio interfera
de manera extraa en la transmisin de datos cuando iniciaba una grabacin (el
programa en VB se colgaba durante la grabacin)

[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 89
Conociendo al SnoopyPRO
saban que existen unas aplicaciones (software y software+hardware) que hacen de
analizadores de protocolos para puertos USB.? existen muchos, hay uno llamado
SnoopyPro. (licencia GPL)
me di curiosidad y lo baj. lo primero ver las instrucciones:
1
2
3
4
5
6
7
8
9
1
0
1
1
1
2
1
3
1
4
1
5
1
6
1
7
SnoopyPro is a tool for advanced USB programmers. It allows you to
record each URB sent to and received from a USB device. This traces
can be saved, loaded, edited, printed and combined into new traces.

WARNING: You might damage your system with this tool. Don't use it
if you don't know what you're doing!!!! We're not responsible for
anything that happens to you, your system, your devices, your
marriage, etc. etc.
...

====================================================================
======
INSTALLATION/USE:
====================================================================
======

1. Run SnoopyPro.exe from whereever you have saved it.
2. Open up the USB devices window with F2.
3. Choose 'Unpack Drivers' from the 'File' menu.
4. Choose 'Install Service' from the 'File' menu.
5. Locate the device you want to sniff.
6. Right-click on it and choose 'Install and Restart'.
7. Wait for the magic to happen...
...

Ventana Principal del SnoopyPro
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 90
siguiendo los pasos1,2,3 y buscamos el COM4 de nuestro ejemplo anterior

Iniciando el SnoopyPro
cargamos la aplicacin en VB

[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 91
Probando el SnoopyPro
despus de clicar varias veces en el botn Enviando a al PIC detenemos el escaneo:

Escaneando el puerto USB
empezamos a husmear. Despus de unas decenas de lneas nos encontramos con esta:

Analizando trfico del puerto USB
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 92
abrimos a ver que hay:

leyendo parmetros capturados
coincide con el carcter a que se enva al PIC en hexa coincidencia?. si miramos
unas lneas mas abajo, no encontramos con un par de caracteres mas y una cadena:

Comparacin entre parmetros
la coincidencia a la que me refiero es que la cadena que enva el PIC al PC es:
Lleg la letra a
cuya interpretacin en hexa sera:
4C 6C 65 67 F3 20 6C 61 20 6C 65 74 72 61 20 61
muy interesante!

[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 93
Estudio de mpusbapi.dll (parte I)
vamos a estudiar en forma la transmisin USB usando la biblioteca de vnculo dinmico
mpusbapi.dll y que mejor que empezar con el ejemplo de J1M. hay que tener una idea
de porque Jaime utiliz esas llamadas a los drivers y que hace cada una de ellas.
hay muchas preguntas en cuanto a este tipo de transmisin, por ejemplo:
podemos transmitir a 12Mbits/seg en lenguaje C?
si estamos ejecutando un proceso de muestreo, podremos llegar a esa velocidad?
las posibles respuestas a estas, sin nimo de desilusionar a nadie (incluyndome) vean
esto (mitos y realidades pgina 9 de 858_USB.pdf):

Mitos y verdades acerca del USB
una cosa que hay que tener en consideracin y sobre todo para lo que estudiamos esto
en lenguaje de alto nivel, el protocolo de transmisin USB tambin lo llaman la pila
USB
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 94

reas Implementadas de la pila USB
tomado de usb_20.pdf, figura 5-2, pg26
observen que tiene cierto parecido al modelo OSI. en las capas superiores tenemos las
funciones bsicas que el usuario puede realizar (comunicacin lgica). esto a su vez va
a parar a la segunda capa y luego a la tercera capa(comunicacin fsica) que involucra el
aspecto elctrico. En nuestro caso estaramos directamente metidos en la capa superior,
pero algunas veces entrando en las otras dos:
primera capa(superior): programacin bsica en C.
segunda capa(intermedio): llamados a los drivers que trae el compilador de C.
tercera capa(inferior): llamados a los drivers que trae el compilador de C (procesos
dentro de los drivers) y conexin del mdulo USB al HOST.
esta tema es fascinante pero a la vez extenso, as que hay que ir por partes para no
perdernos.
- ESTUDIO DEL LADO DEL PIC:
por lo pronto lo que hay que hacer, es estudiar los drivers que trae el CCS (que es el
compilador de C que uso), estos son:


- pic18_usb.h
- PicUSB.h
- usb.c
- usb.h


[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 95
tratando de meter un poco de teora a cada lnea que nos encontremos y siguiendo el
mismo mtodo anterior: analizando el cdigo a la inversa.
veamos el cdigo reza as:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
//// PicUSB.c
////
////
////
//// Este ejemplo muestra como desarrollar un sencillo dispositivo
////
//// USB con el PIC18F2550, aunque puede ser facilmente adaptado
////
//// para la serie 18Fxx5x. Se suministra el PicUSB.exe, as como
////
//// su cdigo fuente para Visual C# 2005, podris encontrar tb
////
//// los drivers para el dispositivo. No se suministra esquema de
////
//// conexin puesto que est pensado para ser usado en el GTP USB,
////
//// cualquiera de las tres versiones disponibles, si aun no teneis
////
//// el programador, podeis utilizar el esquema de ese proyecto.
////
////
////
//// Cuando el dispositivo sea conectado al PC, saldr el asistente
////
//// para la instalacin del driver. Instala el suministrado junto
////
//// a este ejemplo, lo encontrareis dentro de la carpeta Driver.
////
//// Una vez instalado podreis usar el PicUSB.exe para encender o
////
//// apagar el led bicolor del GTP USB, y para realizar la suma de
////
//// dos nmeros introducidos.
////
////
////
//// Realizado con el compilador CCS PCWH 3.227
////
////
////
//// Por: Jaime Fernndez-Caro Belmonte hobbypic@hotmail.com
////
////
////
//// http://www.hobbypic.com
////
///////////////////////////////////////////////////////////////////
//////
#include <18F4550.h>
//#fuses
HSPLL,NOWDT,NOPROTECT,NOLVP,NODEBUG,USBDIV,PLL3,CPUDIV1,VREGEN
#fuses
XTPLL,MCLR,NOWDT,NOPROTECT,NOLVP,NODEBUG,USBDIV,PLL1,CPUDIV1,VREGEN
,NOPBADEN // el fuse
// modificado para USB -> VREGEN
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 96
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
10
0
10
1
10
2
10
3
10
4
10
5
10
6
10
7
10
#use delay(clock=48000000)

///////////////////////////////////////////////////////////////////
//////////
//
// CCS Library dynamic defines. For dynamic configuration of the
CCS Library
// for your application several defines need to be made. See the
comments
// at usb.h for more information
//
///////////////////////////////////////////////////////////////////
//////////
#define USB_HID_DEVICE FALSE //deshabilitamos el
uso de las directivas HID
#define USB_EP1_TX_ENABLE USB_ENABLE_BULK //turn on
EP1(EndPoint1) for IN bulk/interrupt transfers
#define USB_EP1_RX_ENABLE USB_ENABLE_BULK //turn on
EP1(EndPoint1) for OUT bulk/interrupt transfers
#define USB_EP1_TX_SIZE 1 //size to allocate for
the tx endpoint 1 buffer
#define USB_EP1_RX_SIZE 3 //size to allocate for
the rx endpoint 1 buffer


///////////////////////////////////////////////////////////////////
//////////
//
// If you are using a USB connection sense pin, define it here. If
you are
// not using connection sense, comment out this line. Without
connection
// sense you will not know if the device gets disconnected.
// (connection sense should look like this:
// 100k
// VBUS-----+----/\/\/\/\/\----- (I/O PIN ON PIC)
// |
// +----/\/\/\/\/\-----GND
// 100k
// (where VBUS is pin1 of the USB connector)
//
///////////////////////////////////////////////////////////////////
//////////
//#define USB_CON_SENSE_PIN PIN_B2 //CCS 18F4550 development kit
has optional conection sense pin

///////////////////////////////////////////////////////////////////
//////////
//
// Include the CCS USB Libraries. See the comments at the top of
these
// files for more information
//
///////////////////////////////////////////////////////////////////
//////////
#include <pic18_usb.h> //Microchip PIC18Fxx5x Hardware layer
for CCS's PIC USB driver
#include <PicUSB.h> //Configuracin del USB y los
descriptores para este dispositivo
#include <usb.c> //handles usb setup tokens and get
descriptor reports
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 97
8
10
9
11
0
11
1
11
2
11
3
11
4
11
5
11
6
11
7
11
8
11
9
12
0
12
1
12
2
12
3
12
4
12
5
12
6
12
7
12
8
12
9
13
0
13
1
13
2
13
3
13
4
13
5
13
6


///////////////////////////////////////////////////////////////////
//////////
//
// Al conectar el PicUSB al PC encendemos el Led Rojo hasta que el
dispositivo
// halla sido configurado por el PC, en ese momento encederemos el
Led Verde.
// Esperaremos hasta que se reciba un paquete proveniente del PC.
Comprobaremos
// el primer byte del paquete recibido para comprobar si queremos
entrar en el
// modo Suma, donde se realizar una suma de dos operandos, que
corresponderan
// con los dos bytes restantes del paquete recibido; una vez
realizada la suma
// enviaremos el paquete con el resultado de vuelta al PC. Si
entramos en el
// modo Led comprobaremos el segundo byte del paquete recibido para
comprobar
// si deberemos apagar los leds, encender el verder o el rojo.
//
///////////////////////////////////////////////////////////////////
//////////
#define LEDV PIN_B6
#define LEDR PIN_B7
#define LED_ON output_high
#define LED_OFF output_low

#define modo recibe[0]
#define param1 recibe[1]
#define param2 recibe[2]
#define resultado envia[0]


void main(void) {

int8 recibe[3]; //declaramos variables
int8 envia[1];

LED_OFF(LEDV); //encendemos led rojo
LED_ON(LEDR);

usb_init(); //inicializamos el USB

usb_task(); //habilita periferico usb e
interrupciones
usb_wait_for_enumeration(); //esperamos hasta que el PicUSB
sea configurado por el host

LED_OFF(LEDR);
LED_ON(LEDV); //encendemos led verde

while (TRUE)
{
if(usb_enumerated()) //si el PicUSB est configurado
{
if (usb_kbhit(1)) //si el endpoint de salida
contiene datos del host
{
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 98
usb_get_packet(1, recibe, 3); //cojemos el paquete de
tamao 3bytes del EP1 y almacenamos en recibe

if (modo == 0) // Modo_Suma
{
resultado = param1 + param2; //hacemos la suma

usb_put_packet(1, envia, 1, USB_DTS_TOGGLE);
//enviamos el paquete de tamao 1byte del EP1 al PC
}

if (modo == 1) // Modo_Led
{
if (param1 == 0) {LED_OFF(LEDV); LED_OFF(LEDR);}
//apagamos los leds
if (param1 == 1) {LED_ON(LEDV); LED_OFF(LEDR);}
//encendemos led verde
if (param1 == 2) {LED_OFF(LEDV); LED_ON(LEDR);}
//encendemos led rojo
}
}
}
}
}
all estn las funciones usb_task(), usb_init() que ya las vimos por encimita, la novedad
son las funciones: usb_wait_for_enumeration(), usb_get_packet y usb_put_packet
tambin estn las definiciones USB_EP1_TX_ENABLE USB_ENABLE_BULK
comencemos por el principio (lgico no? )

#define USB_HID_DEVICE FALSE //deshabilitamos el uso de las directivas HID


Qu significa HID?


HID es acrnimo en espaol de Dispositivo de Interfaz Humana como bien lo describe
Diego en su artculo EL USB DESENCADENADO : HID USB
y resulta que en los drivers del CCS viene activado por defecto.
si lo vamos a usar, no colocamos nada. si NO lo usaremos, lo negamos en el define (est
programado al revs, digo yo )
#define USB_EP1_TX_ENABLE USB_ENABLE_BULK //turn on EP1(EndPoint1) for
IN bulk/interrupt transfers
que es eso de endpoint? bulk/interrup transfers?
voy a colocar aqu una explicacin que me pareci excelente tomada de un proyecto
especial de grado link Capitulo 3: Bus Serie Universal, funcionamiento Pg. 38
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 99
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
cita:
...
"Los dispositivos (o mejor dicho, las funcionas) tienen asociados
unos canales
lgicos unidireccionales (llamados pipes) que conectan al host
controlador con
una entidad lgica en el dispositivo llamada endpoint. Los datos son
enviados
en paquetes de largo variable (potencia de 2). Tpicamente estos
paquetes son
de 64, 128 o ms bytes.
Estos endpoints (y sus respectivos pipes) son numerados del 0 al 15
en cada
direccin, por lo cual un dispositivo puede tener hasta 32 endpoints
(16 de
entrada y 16 de salida). La direccin se considera siempre desde el
punto de
vista del host controlador. As un endpoint de salida ser un canal
que
transmite datos desde el host controlador al dispositivo. Un
endpoint solo
puede tener una nica direccin. El endpoint 0 (en ambas
direcciones) est
reservado para el control del bus."
...
Se puede decir que los endpoint son buffer temporales de datos de entrada/salida en
cada tipo. En el mdulo USB existen 16 de salida (OUT) y 16 de entrada (IN) pero
agrupados en forma bidirecional, de acuerdo a un par de bits de configuracin (ver Pg.
171). Ojo un endpoint es unidireccional.
para quien tenga dudas con el pipe, una imagen representativa:

Flujo de Comunicacin del USB
ver Pg. 33 usb_20.pdf
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 100
respecto a la otra pregunta, existen 4 tipos de transferencias:
transferencias de control:
usado para comandos (y respuestas) cortos y simples. Es el tipo de transferencia usada
por el pipe 0
transferencias iscronas:
proveen un ancho de banda asegurado pero con posibles prdidas de datos. Usado
tpicamente para audio y video en tiempo real
transferencias interruptivas:
para dispositivos que necesitan una respuesta rpida (poca latencia), por ejemplo, mouse
y otros dispositivos de interaccin humana.
transferencias masivas (BULK):
para transferencias grandes y espordicas utilizando todo el ancho de banda disponible,
pero sin garantas de velocidad o latencia. Por ejemplo, transferencias de archivos.
entonces nosotros debemos definir que tipo de transferencia vamos a realizar.
en el ejemplo de Jaime se estn declarando 2 endpoints (1 bidirecionales) como
transferencia masiva o BULK.
#define USB_EP1_TX_SIZE 1 //size to allocate for the tx endpoint 1 buffer
podemos definir el tamao del buffer en bytes, el lmite lo tendremos que buscar en el
driver correspondiente (con FS hasta 64 bytes por transaccin).
nota: no confundir FS con HS, con High Speed se llega hasta 480Mbps, el mdulo USB
del pic soporta Full Speed = 12Mbps
usb_wait_for_enumeration() segn el concepto que dan en el driver, hace lo mismo que
usb_enumerated(). La diferencia est en que el primero se queda en un bucle indefinido
hasta que el HOST le d la orden de habilitacin.
para propsitos donde queramos hacer otras actividades en el PIC, usaremos el segundo.
ahora hablaremos de como se hace para transmitir y recibir datos. para eso estn
usb_put_packet(,,) y usb_get_packet(,,) ambas necesitan de 3 argumentos. vamos con
put_packet:
1
2
3
4
5
6
7
8
9
10
11
12
...
/* usb_put_packet(endpoint,*ptr,len,toggle)
/*
/* Input: endpoint - endpoint to send packet to
/* ptr - points to data to send
/* len - amount of data to send
/* toggle - whether to send data with a DATA0 pid, a DATA1
pid, or toggle from the last DATAx pid.
/*
/* Output: TRUE if data was sent correctly, FALSE if it was not.
The only reason it will
/* return FALSE is if because the TX buffer is still full
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 101
13
14
15
16
17
18
19
from the last time you
/* tried to send a packet.
/*
/* Summary: Sends one packet out the EP to the host. Notice that
there is a difference
/* between a packet and a message. If you wanted to send a
512 byte message you
/* would accomplish this by sending 8 64-byte packets,
followed by a 0 length packet.
/* If the last (or only packet) being sent is less than the
max packet size defined
/* in your descriptor then you do not need to send a 0
length packet to identify
/* an end of message.
...
el 1 argumento endpoint ya se explic.
- el 2 argumento apunta a la direccin del dato a enviar (es una variable declarada por
nosotros).
- el 3 argumento es el tamao del paquete en bytes.
- el 4 argumento habla sobre DATA1, DATA2, toggle. y eso que es?
como parte de su protocolo, nos encontraremos entre otras cosas que USB maneja la
transmisin de datos por paquetes, llamados TOKEN en la cul el HOST es el iniciador
de todas las transferencias que se producen en el BUS [2]

Los paquetes de datos
ver Pg. 206 usb_20.pdf
pues bien en la parte de transmisin de datos USB, los paquetes de datos se encuentran
en grupos de paquetes de datos, y dentro de estos, existen unos llamados DATA0,
DATA1. hay un proceso llamado sincronizacin del data toggle. a grandes rasgos esto
no es mas que un mtodo de validacin de paquetes, y lo que hace es enviar
alternadamente a DATA0 y DATA1 en una secuencia seguido de su ACK respectivo.
todo con el objetivo de mantener la sincronizacin transmisor <-> receptor.
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 102

Transacciones Consecutivas
ver Pg. 233 usb_20.pdf
ese tercer argumento definido en el cdigo ejemplo: USB_DTS_TOGGLE
1
2
enum USB_DTS_BIT {USB_DTS_DATA1=1, USB_DTS_TOGGLE=2, USB_DTS_DATA0=0,
USB_DTS_STALL=3, USB_DTS_USERX=4};
segn la pgina 174 de 39632c.pdf el data toggle est definido por un bit llamado
DTSEN y es mas, all lo explican.

Bit DTSEN en recepcin de paquetes
hay toda una teora en lo relacionado a los grupos de paquetes, no lo mencionar para
no salirme del objetivo principal.
seguro alguien preguntar, y si yo no quiero usar la sincronizacin del data toggle?
esto depende del tipo de transferencia a usar, hay casos donde es recomendable usarlo.
ej: transferencias de mltiples transacciones y casos donde no se puede usar. para mayor
informacin ver paginas 56 y 232 de usb_20.pdf


usb_get_packet()
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 103
1
2
3
4
5
6
7
8
9
1
0
1
1
1
2
1
3
1
4
1
5
1
6
1
7
/*******************************************************************
************
/* usb_get_packet(endpoint, *ptr, max)
/*
/* Input: endpoint - endpoint to get data from
/* ptr - where to save data to local PIC RAM
/* max - max amount of data to receive from buffer
/*
/* Output: the amount of data taken from the buffer.
/*
/* NOTE - IF THERE IS NO PACKET TO GET YOU WILL GET INVALID
RESULTS!
/* VERIFY WITH USB_KBHIT() BEFORE YOU CALL
USB_GET_PACKET()!
/*
/* Summary: Gets a packet of data from the USB buffer and puts into
local PIC RAM.
/* Until you call usb_get_packet() the data will sit in the
endpoint
/* buffer and the PC will get NAKs when it tries to write
more data
/* to the endpoint.
...
el argumento 1 es el buffer de datos de entrada, donde llega el paquete de datos.
el argumento 2 es el apuntador adonde guardaremos ese dato.
el argumento 3 es el tamao de paquete en bytes.
-vaya- se fue todo en pura teora, entonces en la prxima parte veremos si hacemos el
estudio del lado del HOST mediante mpusbapi.dll y como hacerla funcionar por ej: en
VB a travs de una Interfaz de Programacin de Aplicaciones API
Fuentes Consultadas (Lectura sper altamente recomendadas para leer):
858 USB Introduction to Full-Speed USB
Manual de Formacin de USB
Universal Serial Bus Specification 2.0
INGENIERA EN MICROCONTROLADORES - Protocolo USB
un paseo por usb

Osciloscopio USB. Documentacin autores: Pablo Hoffman y Martn Szmulewicz


este ltimo viene de:
http://pablohoffman.com/oscusb/doc/
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 104
http://pablohoffman.com/oscusb/
Osciloscopio USB abierto
Protocolo USB aplicado a placas con microcontroladores

[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 105
Estudio de mpusbapi.dll (parte II)
para hacer este estudio vamos a ver unos ejemplos de Slalen(programa1) y Ernesto
Mozota Navarro(programa2). Este ltimo lo pueden bajar de http://www.hobbypic.com/
ambos sirven para el firmware que escribi Jaime J1M, el programa2 tambin aade
otras posibilidades (PWM, CAD)
lo primero, probar el cdigo. Claro! jeje y grabar el firmware PICusb en el PIC. Esto ya
lo hice varios post atrs, pero no lo expliqu y ahora le toca el turno al Visual Basic
usando el programa1.
como mencion anteriormente, para usar nuestra aplicacin corriendo en VB, tenemos
que hacer uso de unas llamadas a la librera mpusbapi.dll (apis).
1
2
3
4
5
6
7
Public Declare Function MPUSBGetDLLVersion Lib "mpusbapi.dll" () As
Long
Public Declare Function MPUSBGetDeviceCount Lib "mpusbapi.dll" (ByVal
pVID_PID As String) As Long
Public Declare Function MPUSBOpen Lib "mpusbapi.dll" (ByVal instance
As Long, ByVal pVID_PID As String, ByVal pEP As String, ByVal dwDir
As Long, ByVal dwReserved As Long) As Long
Public Declare Function MPUSBClose Lib "mpusbapi.dll" (ByVal handle
As Long) As Long
Public Declare Function MPUSBRead Lib "mpusbapi.dll" (ByVal handle As
Long, ByVal pData As Long, ByVal dwLen As Long, ByRef pLength As
Long, ByVal dwMilliseconds As Long) As Long
Public Declare Function MPUSBWrite Lib "mpusbapi.dll" (ByVal handle
As Long, ByVal pData As Long, ByVal dwLen As Long, ByRef pLength As
Long, ByVal dwMilliseconds As Long) As Long
Public Declare Function MPUSBReadInt Lib "mpusbapi.dll" (ByVal handle
As Long, ByVal pData As Long, ByVal dwLen As Long, ByRef pLength As
Long, ByVal dwMilliseconds As Long) As Long
aqu aparecen 7 ,yo cont unas 10 en el cdigo fuente. parece que estas 7 son las
necesarias para hacer transacciones a la funcin.
nota: funcin = dispositivo = mdulo USB del PIC, en adelante me referir a
dispositivo para no confundir cuando hable de funciones en C.
la api mas sencilla aqu, parecer ser la de mostrar la versin
veamos que dice la traduccin que nos pas Slalen:
1
2
MPUSBGetDLLVersion(Void)
Lee el nivel de revision del MPUSAPi.dll. Es un nivel de revision de
32bits. Esta funcion no devuelve la version del codigo, no realiza
nada con el USB.
yo le agregara que devuelve un dato de 32 bits, la versin de la dll en formato
MMMMmmmm.
vamos agregar un procedimiento para ver que hace:
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 106
1
2
3
4
5
Private Sub Command2_Click()
Dim version_dll As Long
version_dll = Hex(MPUSBGetDLLVersion)
MsgBox Str(version_dll)
End Sub

Mostrar la versin de mpusbapi.dll
nos arroja 10000, y pienso que como hay 8 dgitos, ya que la versin es en hexa (8
nibbles = 32bits) -> versin dll = 1.0.0.0.0
si quieren mas informacin acerca de estas funciones, visitar estas direcciones:
- La mpusbapi.dll desencadenada: PC <-> PIC va USB en Delphi
- Traduccin de mpusbapi.doc
de lo que si voy hablar es como podemos usar esas apis en VB.
veamos:
cuando arrancamos esta aplicacin, primero se debe ejecutar el form_load
1
2
3
Private Sub Form_Load()
OpenMPUSBDevice 'abre comunicaciones
End Sub


quin es openMPUSBDevice?


R: ste llama a MPUSBOpen:
1
2
3
4
Sub OpenMPUSBDevice()
myOutPipe = MPUSBOpen(0, vid_pid, out_pipe, 0, 0) 'como
salida
myInPipe = MPUSBOpen(0, vid_pid, in_pipe, 1, 0) 'como
entrada
End Sub
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 107
configura el conducto(pipe) de acceso a cada endpoint, uno de salida y uno de entrada.
para outpipe tenemos operacin de escritura -> MP_WRITE=0 y para inpipe ->
MP_READ=1. El resultado de esta llamada se guardar en my(In/Out)Pipe
si para ambos tenemos como resultado -1 -> entonces quiere decir que no se pudo
establecer el enlace lgico con el dispositivo.


INVALID_HANDLE_VALUE = -1
si observan el programa2 notaran que hay comprobaciones en casi todas partes,
preguntando si hay enlace.
para terminar la aplicacin, debemos cerrar el enlace (igual como se hace en RS-232)
mediante:
1
2
3
4
Sub CloseMPUSBDevice()
MPUSBClose (myOutPipe)
MPUSBClose (myInPipe)
End Sub
esto es parecido al sistema de mensajeria de windows, donde el resultado de una api, es
utilizada por otra (handle) para ejecutar otros procesos.
nota: es bueno aadirle el mtodo debug.print a cada api para poder analizar cada lnea
ejecutada:
1
2
3
4
5
6
7
Sub OpenMPUSBDevice()
myOutPipe = MPUSBOpen(0, vid_pid, out_pipe, 0, 0) 'como
salida
Debug.Print "myOutPipe= " & myOutPipe

myInPipe = MPUSBOpen(0, vid_pid, in_pipe, 1, 0) 'como
entrada
Debug.Print "myInPipe= " & myInPipe
End Sub
vamos a escribir un cdigo para abrir y cerrar un enlace virtual con el dispositivo. les
parece?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
Option Explicit

Private Declare Function MPUSBOpen Lib "mpusbapi.dll" (ByVal
instance As Long, ByVal pVID_PID As String, ByVal pEP As String,
ByVal dwDir As Long, ByVal dwReserved As Long) As Long
Private Declare Function MPUSBClose Lib "mpusbapi.dll" (ByVal handle
As Long) As Long

Const INVALID_HANDLE_VALUE = -1
Const MPUS_FAIL = 0
Const MPUSB_SUCCESS = 1


Const vid_pid = "vid_04d8&pid_0011" ' Vendor id (Microchip) y
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 108
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
Periferico id
Const out_pipe = "\MCHP_EP1" ' endpoint 1
Const in_pipe = "\MCHP_EP1" ' endpoint 1

Const MP_WRITE = 0 '
Const MP_READ = 1

Public myInPipe As Long ' para guardar el manejador
Public myOutPipe As Long


Private Sub cmdabrir_Click() ' abrir enlace o pipe
myOutPipe = MPUSBOpen(0, vid_pid, out_pipe, 0, 0)
'como salida
Debug.Print "myOutPipe= " & myOutPipe ' para monitoreo

If myOutPipe = INVALID_HANDLE_VALUE Then ' si es -1
lblpipeout = "Fallo el enlace de salida"
Else
lblpipeout = "Enlace salida establecido"
End If

myInPipe = MPUSBOpen(0, vid_pid, in_pipe, 1, 0)
'como entrada
Debug.Print "myInPipe= " & myInPipe

If myInPipe = INVALID_HANDLE_VALUE Then
lblpipein = "Fallo el enlace de entrada"
Else
lblpipein = "Enlace entrada establecido"
End If

End Sub

Private Sub cmdcerrar_Click() ' cerrar enlace pipe
Dim resul_o As Long: Dim resul_i As Long
resul_o = MPUSBClose(myOutPipe)
Debug.Print "MPUSBClose(myOutPipe)= " & resul_o
If resul_o = MPUSB_SUCCESS Then
lblpipeout.Caption = "Enlace salida cerrado"
Else
lblpipeout.Caption = "Error al cerrar el enlace salida,
puede que este cerrado"
End If
resul_i = MPUSBClose(myInPipe)
Debug.Print "MPUSBClose(myInPipe)= " & resul_i
If resul_i = MPUSB_SUCCESS Then
lblpipein.Caption = "Enlace entrada cerrado"
Else
lblpipein.Caption = "Error al cerrar el enlace entrada,
puede que este cerrado"
End If
End Sub
algunas pantallas de nuestro programilla abriendo y cerrando pipes
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 109

Casos de abrir y cerrar PiPES

Casos de abrir y cerrar PiPES
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 110

Casos de abrir y cerrar PiPES

Casos de abrir y cerrar PiPES
ya tenemos una idea de como se usa la api MPUSBOpen.

[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 111
Estudio de mpusbapi.dll (parte III)
veremos las apis mas importantes de la biblioteca mpusbapi.dll. Me refiero a:
MPUSBRead
MPUSBWrite


- como hizo el programa1 para encender un led?
R: en el botn verde, tenemos:
1
2
3
4
5
Private Sub Command1_Click(Index As Integer)
Send_Buf(0) = 1 'Para que reconozca que se encienden o apagan
Leds
Send_Buf(1) = Index
Send Send_Buf, 2
End Sub
aj ya empezaron las dudas, vamos a ver quien es Send_Buf:
1
2
3
4
5
6
7
8
9
Dim Send_Buf(0 To 2) As Byte
...

' Funcin enviar

Function Send(ByRef SendData() As Byte, bytes As Integer) As Long
Dim SentDataLength As Long
Call MPUSBWrite(myOutPipe, VarPtr(SendData(0)), bytes,
VarPtr(bytes), 1000) 'VarPtr()= puntero a la variable
End Function
es lgico pensar que como se trabaja con bytes, entonces para varios datos es necesario
crear arrays de bytes. y eso es precisamente lo que hace Send_Buf()
aqu hay una sentencia curiosa VarPtr(), yo nunca la haba visto, adems no pertenece al
VB en s, leyendo por aqu, por ac, consegu:
1
2
3
4
Declare Function VarPtrAny Lib "vb40032.dll" Alias "VarPtr" (lpObject
As Any) As Long
'The VarPtr-function retrieves the memory handle of an object.
' lpObject
' Handle that identifies the object
-ahh- conque viene del runtime!
hurgando en la biblioteca MSDN, aparecen tres mtodos NO documentados sobre usar
direccionamiento en VB, VarPtr, ObjPtr y StrPtr
esto si es un descubrimiento para mi, el uso de punteros en basic (bajo ciertas
condiciones).
volviendo a la api MPUSBWrite, el segundo argumento:
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 112
pData -> salida: puntero al buffer que contiene los datos que se van a escribir


para explicar un momento el uso del puntero en este caso, este argumento lo que
necesita es la direccin donde est alojado el dato que queremos enviar
el problema que tiene visual basic es que no podemos usar punteros, pero con el mtodo
varptr podemos tomar dicha direccin, y esto no es lo mejor de todo, lase bien. Lo
mejor es que gracias a que en un array de bytes las direcciones de esos datos son
contiguos, entonces con solo tener la direccin del primer byte de datos es lo necesario
que debe tener la api para hacer el recorrido en memoria.
para demostrar esto que estoy diciendo, voy a escribir un cdigo donde:


- guardar un dato (byte) en 2 variables
- tomar la direccin de esas 2 variables mediante varptr
- luego llamando una api CopyMemory, recuperar el valor que hay en
esas direcciones que vienen siendo el mismo dato.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
' mediante el uso de Varptr y CopyMemory
' Varptr(dato): devuelve la direccion (Long) donde se almacena la
variable dato
' con CopyMemory podemos recuperar el dato en memoria a partir de su
direccion

' por: Pedro - PalitroqueZ. 23-feb-2007 10:19AM

Option Explicit

Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory"
(pDst As Any, pSrc As Long, ByVal ByteLen As Long)

Dim d(0 To 1) As Byte, dato(0 To 1) As Byte, r1 As Long, r2 As Long

Private Sub Command1_Click()
d(0) = 25 ' un valor cualquiera
Debug.Print "d(0)= " & d(0)
d(1) = 97 ' un valor cualquiera
Debug.Print "d(1)= " & d(1)

r1 = VarPtr(d(0)) ' en r1 se guarda la direccion donde esta
almacenado d(0)
Debug.Print "r1= " & r1

r2 = VarPtr(d(1))
Debug.Print "r2= " & r2

' ahora se procede a recuperar el dato, usando CopyMemory
CopyMemory ByVal VarPtr(dato(0)), ByVal r1, 2
' debe usarse byval OBLIGATORIO para que se pueda copiar el dato
en vez de la direccion

' el ultimo argumento corresponde a la longitud del dato en
bytes
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 113
36
37
38
39
40
41
' si se coloca 2, es para que tome la direccion del dato
contiguo
' es decir, dato(1).
' como dato(0), dato(1) -> se almacenan en direcciones contiguas
' entonces CopyMemory almacenara el par de bytes de datos, en
dato(0)
' y dato(1) mediante sus direcciones respectivas

Debug.Print "dato(0)= " & dato(0)
Debug.Print "dato(1)= " & dato(1)
MsgBox "se recuper d(0)=" & Str(dato(0)) & " y d(1)=" &
Str(dato(1))

Unload Me
End Sub
una imagen del debugger:

Usando punteros en Visual Basic 6
as pues, donde veamos el varptr ya sabemos a que se est refiriendo, adems el
argumento de la api tambin lo delata con la letra p ej: pData, pLenght
esto es la parte complicada de entender el uso de la api, para MPUSBRead es similar y
al revs, el segundo argumento es el puntero de una variable previamente declarada por
nosotros para que se alojen los datos que vayan llegando del USB.
como vern esta es otra aplicacin del concepto del puntero, por un lado tenemos la
casilla(direccin de almacenamiento) y por el otro tenemos el valor del dato
almacenado.
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 114
el resto de los argumentos es fcil de entender, como la longitud del dato (en bytes).
esto depende de como configuremos el envo desde el dispositivo
el tiempo en milisegundos: es para que la api no se quede en un bucle infinito si llegara
a ocurrir un problema
y por supuesto el pipe, o mejor dicho el handle del pipe, que se puede decir que es un
puntero representado en VB como un long (ver fuentes consultadas)
bueno volviendo al uso de la funcin Send
1
2
3
Send_Buf(0) = 1 'Para que reconozca que se encienden o apagan
Leds
Send_Buf(1) = Index
Send Send_Buf, 2
esto interpretado desde el punto de vista del micro, es un paquete de datos, donde hay 2
bytes. en el primer byte se guarda el modo (modo_led) y el en otro byte se guarda el
paraml que es la accin para ambos leds (apagado, on, off -> led rojo y verde)
luego el array de bytes se enva a la funcin send
1
2
3
4
Function Send(ByRef SendData() As Byte, bytes As Integer) As Long
Dim SentDataLength As Long
Call MPUSBWrite(myOutPipe, VarPtr(SendData(0)), bytes,
VarPtr(bytes), 1000) 'VarPtr()= puntero a la variable
End Function
observen el VarPtr(SendData(0)), es lo mismo que habl hace rato, se toma la direccin
del primer byte es lo nico que necesita pData para tomar el resto del array de datos
el que falta, la suma:
1
2
3
4
5
6
7
8
9
10
11
12
Dim a As Byte 'buffer de datos intermedio

Send_Buf(0) = 0 'Para que reconozca que es una suma
a = CByte(sumando(0).Text) 'convierte el texto a byte
Send_Buf(2) = a
Send_Buf(0) = 0
a = CByte(sumando(1).Text)
Send_Buf(1) = a
Send_Buf(0) = 0
Send Send_Buf, 3 'enva los sumandos
recibir (a) 'recibe el resultado
resultado.Caption = CStr(rec) 'convierte el dato a string
el Send ya lo hablamos, falta la funcin recibir:
1
2
3
Dim SentDataLength As Long
Call MPUSBRead(myInPipe, VarPtr(s), 1, 1, 1000)
rec = s 'guardo el dato recibido en una variable
intermedia
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 115
aqu sucede lo contrario, es decir, la api MPUSBRead necesita la direccin del byte s
para almacenar el dato que viene del PIC (que en este caso es 1 byte de longitud).
esto fue el anlisis realizado al programa1 y programa2.
vamos a usar el estupendo SnoopyPro para ver los bferes del USB jijiji
abrimos y ejecutamos las siguientes acciones en secuencia:


1.- led rojo = ON
2.- led verde = ON
3.- apaga leds
4.- 1 + 0 = 1
5.- 1 + 7 = 8
6.- 12 + 7 = 19

Capturas con SnoopyPro
a ver que tenemos all:

[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 116
Transaccin Recibida
tenemos un paquete de 2 bytes, en el primer el modo = 1 (modo led). y en el segundo
paraml = 2 (led rojo ON)

Transaccin Recibida
tenemos un paquete de 2 bytes, en el primer el modo = 1 (modo led). y en el segundo
paraml = 1 (led verde ON)

Transaccin Recibida
tenemos un paquete de 2 bytes, en el primer el modo = 1 (modo led). y en el segundo
paraml = 0 (led rojo y verde off)

Transaccin Recibida
tenemos un paquete de 3 bytes, en el primer el modo = 0 (modo suma). y en el segundo
y tercer byte tenemos 0 y 1 que son los operandos de la suma. ojo vean que esto es un
paquete down , que transmite HOST -> PIC.
un poco mas abajo:
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 117

Contenido paquete
tenemos un paquete de PIC -> HOST de 1 byte y que trae? nada mas y nada menos que
el resultado de la suma.
el par de sumas que faltan:

analizando paquetes
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 118

analizando paquetes
observaciones:
- despus de haber visto varias veces el cdigo de Jaime hasta ahora es que me doy
cuenta que el led verde es RB6 y led rojo RB7 yo lo tena invertido. pero lo extrao de
todo es que con el programa PicUSBDelphi.exe de Diego se ejecuta OK con los leds
invertido. ??
- faltara implementar un algoritmo de validacin, porque si ocurre un problema, hay
que resetear tanto al programa como al pic para normalizar.
- tengo que instalar el driver wdmstub.sys cada vez que conecto el cable USB en un
puerto distinto, no se supone que esos conectores son compartidos?
esto tambin sucede con la clase CDC.


Fuentes consultadas:
-Interacting with Microchip Full-Speed USB Demo Board using Visual Studio Tools
(Part II)
- API-Guide
- MSDN Library

[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 119
Estudio de mpusbapi.dll (parte IV)
quisiera hacer unas observaciones, varios mensaje atrs hablando sobre la api
MPUSBGetDLLVersion() escrib:
cita:
1
nos arroja 10000, y pienso que como hay 8 dgitos, ya que la versin
es en hexa (8 nibbles = 32bits) -> versin dll = 1.0.0.0.0
bueno, ahora no estoy tan seguro que eso sea cierto (despus de todo es una suposicin),
ahora me baso en lo siguiente:
- que dicha api, devuelve un puntero que contiene la versin de la librera mpusbapi.dll
- si esto es cierto, entonces la versin correcta es 0.0.1.0
aqu est un adjunto con un programa en visual basic que hace lo que digo.
est planteado as al momento de escribir esto, pudindose cambiar por la versin
correcta posteriormente (dado el caso).

voy a tomar el ejemplo del CDC explicado con anterioridad y lo voy a modificar para
usarlo con la librera mpusbapi.dll
- lo primero, hacer la deteccin del lado del dispositivo
- lo segundo hacer la deteccin del lado del Host
Deteccin del lado del dispositivo:
es de la misma forma que para la clase CDC estudiada, mediante el
USB_CON_SENSE_PIN
el cdigo con la modificacin:
1
2
3
4
5
6
7
8
9
1
0
1
1
1
/* ejemplo7_parte4.c
se pretende hacer la deteccion de conexion al puerto USB, mediante
la mpusbapi.dll
mostrando en una pantalla LCD 2x16 el estado.

Este codigo es un hibrido del cual se tomo partes de:
- PicUSB.c de J1M
- RRCdcUSB de RedPic
- probando_USB.c del ejemplo6_parte5 de PalitroqueZ

Pedro - PalitroqueZ 07-Mar-2007. Hora: 3:54 PM
*/

#include <18F4550.h>
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 120
2
1
3
1
4
1
5
1
6
1
7
1
8
1
9
2
0
2
1
2
2
2
3
2
4
2
5
2
6
2
7
2
8
2
9
3
0
3
1
3
2
3
3
3
4
3
5
3
6
3
7
3
8
3
9
4
0
4
1
4
2
#fuses
XTPLL,NOMCLR,NOWDT,NOPROTECT,NOLVP,NODEBUG,USBDIV,PLL1,CPUDIV1,VREGE
N,NOPBADEN
#use delay(clock=48000000)

#define use_portb_lcd TRUE

#define USB_HID_DEVICE FALSE //deshabilitamos el uso
de las directivas HID
#define USB_EP1_TX_ENABLE USB_ENABLE_BULK //turn on
EP1(EndPoint1) for IN bulk/interrupt transfers
#define USB_EP1_RX_ENABLE USB_ENABLE_BULK //turn on
EP1(EndPoint1) for OUT bulk/interrupt transfers
#define USB_EP1_TX_SIZE 1 //size to allocate for
the tx endpoint 1 buffer
#define USB_EP1_RX_SIZE 1 //size to allocate for
the rx endpoint 1 buffer

#define USB_CON_SENSE_PIN PIN_E3

#include <pic18_usb.h> //Microchip PIC18Fxx5x Hardware layer for
CCS's PIC USB driver
#include "PicUSB.h" //Configuracin del USB y los descriptores
para este dispositivo
#include <usb.c> //handles usb setup tokens and get
descriptor reports
#include <lcd.c>

void mostrar_estado_usb();

void main(){
int envia[1];
int recibe[1];
envia[0]='a';
usb_init_cs(); // inicializa el USB y lo desactiva
lcd_init(); // llamadas necesarias para iniciar la LCD
while(true){
usb_task(); //habilita periferico usb e interrupciones
mostrar_estado_usb();
if(usb_enumerated()){ // primer if
if(usb_kbhit(1)){ // segundo if
//si el endpoint de salida contiene datos del host
usb_get_packet(1, recibe, 1);
//cojemos el paquete de tamao 1bytes del EP1 y
almacenamos en recibe
if(recibe[0]=='a'){ // tercer if
usb_put_packet(1, envia, 1, USB_DTS_TOGGLE);
//enviamos el paquete de tamao 1byte del EP1 al PC
lcd_gotoxy(1,1);
lcd_putc("llego una a ");
delay_ms(500);
} // fin del tercer if
} // fin del segundo if
} // fin del primer if
lcd_gotoxy(1,1);
lcd_putc("otros procesos");
delay_ms(500);
} // fin del ciclo while
}
/************************************************
// esta llamada imprime en la LCD los estados de conectado
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 121
4
3
4
4
4
5
4
6
4
7
4
8
4
9
5
0
5
1
5
2
5
3
5
4
5
5
5
6
5
7
5
8
5
9
6
0
6
1
6
2
6
3
6
4
6
5
6
6
6
7
6
8
6
9
7
0
7
1
7
2
7
// y desconectado del USB dependiendo de la bandera
// estado_usb
//***********************************************/
void mostrar_estado_usb(){
lcd_gotoxy(10,2);
if(usb_attached()){
lcd_putc(" USB:On");
}else{
lcd_putc("USB:Off");
}
// delay_ms(500);
}
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 122
3
7
4
7
5
http://www.youtube.com/watch?v=2OdNir5O9bo
voy a hacer unas observaciones sobre este programa, porque pas un buen rato tratando
de que funcionara.
- en usb_kbhit(1), el 1 es el endpoint de datos (el argumento es requerido).
- sustitu a usb_init por usb_init_cs porque?
R: aqu entra el simulador paso a paso del MPLAB.
la funcin:
1
2
3
4
5
6
7
void usb_init(void) {
usb_init_cs();

do {
usb_task();
} while (usb_state != USB_STATE_POWERED);
}
se queda en un bucle eterno a menos que el dispositivo sea conectado, pero mi interes es
hacer que el pic haga otras actividades independientemente si est presente no, el
HOST.


usb_init_cs() -> inicializa el mdulo USB y lo desactiva, est bien as que se desactive
por defecto (menos consumo para el circuito).


- entonces como enciendo el mdulo?
para eso est usb_task() dentro del bucle eterno del while(true), en cada instante l
preguntar por el USB_CON_SENSE_PIN y dependiendo del Vusb en este pin, l
activar/desactivar.
ven lo importante que es el USB_CON_SENSE_PIN, basicamente es una deteccin por
hardware, se est sensando si llega voltaje del HOST (Vusb).
- elimin la bandera estado_usb, porque es igual que preguntar por usb_attached(), me
ahorro 1 bit de memoria (que mezquino jaja). Adems que no hay que modificar el
driver original pic18_usb.h
- el resto del cdigo queda igual, solo ajustar los paquetes de datos a 1 byte, usando un
eco. el HOST le enva un carcter (a) y el dispositivo se lo devuelve.
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 123
volver arriba

Estudio de mpusbapi.dll (parte V)
empezaremos hacer modificaciones al ejemplo de Slalen:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
' este programa envia un caracter y recibe un eco del dispositivo
' para confirmacion.
'
'
' adaptacion del programa original de Slalen
' Pedro-PalitroqueZ 07-Mar-2007 Hora: 7:51 PM

Option Explicit
Dim Send_Buf(0) As Byte
Const verde = &HFF00&
Const rojo = &HFF&

Private Sub cmdversiondll_Click()
Dim version_dll As Long, digitos(4) As Byte, cad As String, t As
Integer
version_dll = VarPtr(MPUSBGetDLLVersion) 'toma el puntero de la
version
For t = 0 To 3
digitos(t) = 0 ' limpiar variables
Next t

CopyMemory ByVal VarPtr(digitos(0)), ByVal version_dll, 5
' recupera de la memoria los digitos de la version y lo copia en
digitos()
cad = ""
For t = 0 To 3 ' concatena los digitos en una cadena
cad = cad & Str(digitos(t)) & "."
Next t
lblversiondll.ForeColor = &HFFFF&
lblversiondll.Caption = Left$(cad, Len(cad) - 1) ' muestra la
version
End Sub

Private Sub Command2_Click()
Dim eco As Byte, dato As Long
Timer1.Enabled = False
Send_Buf(0) = Asc("a") 'envia la "a"
OpenMPUSBDevice 'abre comunicaciones
Send Send_Buf, 1
dato = recibir(eco)
If eco = 97 Then
lblrespuesta.Caption = "El dispositivo respondio Exitosamente"
Else
lblrespuesta.Caption = "No hubo respuesta del Dispositivo"
End If
CloseMPUSBDevice 'cierra comunicaciones
Timer1.Enabled = True
End Sub

Private Sub Form_Load()
Timer1.Interval = 50
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 124
52
53
54
55
56
57
58
59
60
61
62
63
Timer1.Enabled = True
End Sub

Private Sub Form_Unload(Cancel As Integer)
CloseMPUSBDevice 'cierra comunicaciones
End Sub

Private Sub Timer1_Timer()
OpenMPUSBDevice 'abre comunicaciones
If (myOutPipe <> INVALID_HANDLE_VALUE) And (myInPipe <>
INVALID_HANDLE_VALUE) Then
shpestado.FillColor = verde
Else
shpestado.FillColor = rojo
End If
CloseMPUSBDevice 'cierra comunicaciones
End Sub
http://www.youtube.com/watch?v=N1xHoPay-LA
como ven lo adapt para transferencias de paquetes de datos de 1 byte, y como siempre
mi empeo en agregarle un sensor de estado del dispositivo, muy similar que con la
clase CDC: un timer abriendo y cerrando el pipe cada 50 mS y preguntando si hubo
enlace.
cabe decir que el cdigo del PIC es el mismo del ejemplo anterior y funciona igual.
en los ensayos en el protoboard
- reconexin de la extensin USB.
- abriendo y cerrando el programa en VB
- incluso se desconect/conect la alimentacin al PIC y los resultados fueron
satisfactorios.

[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 125
Estudio de mpusbapi.dll (Aplicacin)
se acuerdan del ejemplo donde usamos el CAD y hacamos transferencias y otras
actividades? bien vamos a tomar ese ejemplo, pero con la biblioteca mpusbapi.dll y con
los conocimientos aprendidos en el tema Estudio de Grficos en VB vamos a visualizar
los datos obtenidos.
los paquetes de datos se mantienen en 1 byte, hice pruebas con 64 bytes, y los
resultados fueron casi los mismos.
el cdigo del dispositivo:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
/* ejemplo8_parte1.c
adaptacin del ejemplo6parte6. transmision del resultado del CAD
al PC
al puerto USB, mediante la mpusbapi.dll
mostrando en una pantalla LCD 2x16 el resultado del CAD y el
estado USB.

Este cdigo es un hbrido del cul se tom partes de:
- PicUSB.c de J1M
- RRCdcUSB de RedPic
- probando_USB.c del ejemplo6_parte5 de PalitroqueZ

Pedro - PalitroqueZ 08-Mar-2007. Hora: 9:01 AM
*/

#include <18F4550.h>
#DEVICE ADC=8 // cad a 8 bits
#fuses
XTPLL,NOMCLR,NOWDT,NOPROTECT,NOLVP,NODEBUG,USBDIV,PLL1,CPUDIV1,VREGE
N,NOPBADEN
#use delay(clock=48000000)

#define use_portb_lcd TRUE

#define USB_HID_DEVICE FALSE //deshabilitamos el uso
de las directivas HID
#define USB_EP1_TX_ENABLE USB_ENABLE_BULK //turn on
EP1(EndPoint1) for IN bulk/interrupt transfers
#define USB_EP1_RX_ENABLE USB_ENABLE_BULK //turn on
EP1(EndPoint1) for OUT bulk/interrupt transfers
#define USB_EP1_TX_SIZE 1 //size to allocate for
the tx endpoint 1 buffer
#define USB_EP1_RX_SIZE 1 //size to allocate for
the rx endpoint 1 buffer

#define USB_CON_SENSE_PIN PIN_E3
#define DERECHA 0

#include <pic18_usb.h> //Microchip PIC18Fxx5x Hardware layer for
CCS's PIC USB driver
#include "PicUSB.h" //Configuracin del USB y los descriptores
para este dispositivo
#include <usb.c> //handles usb setup tokens and get
descriptor reports
#include <lcd.c>

[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 126
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
10
0
10
1
10
2
10
3
void mostrar_estado_usb();
void config_adcon2(short justificacion);

int value;

void main(){
int i;
int envia[1];
int recibe[1];

set_tris_a(0x1); // Ra[0]=entradas, los demas=salida

usb_init_cs(); // inicializa el USB y lo desactiva
lcd_init(); // llamadas necesarias para iniciar la LCD
setup_adc_ports( AN0 || VSS_VDD ); // canal AN0, Vref+ = Vdd,
Vref- = Vss
config_adcon2(DERECHA); // justificacin derecha, Tacq= 2Tad

while(true){
usb_task(); //habilita periferico usb e interrupciones
mostrar_estado_usb();
envia[0]= read_adc();

for(i=0;i<16;i++){// muestra resultado del CAD en binario,
linea1 LCD
lcd_gotoxy(16-i,1);
lcd_putc((char)(bit_test(envia[0],i)+0x30));
}
printf(lcd_putc,"\n0x%Lx",envia[0]);
// muestra el resultado del CAD en Hexa, linea2 LCD

if(usb_enumerated()){ // primer if
if(usb_kbhit(1)){ // segundo if
//si el endpoint de salida contiene datos del host
usb_get_packet(1, recibe, 1);
//cojemos el paquete de tamao 1bytes del EP1 y
almacenamos en recibe
if(recibe[0]=='a'){ // tercer if
usb_put_packet(1, envia, 1, USB_DTS_TOGGLE);
//enviamos el paquete de tamao 1 bytes del EP1 al
PC
} // fin del tercer if
} // fin del segundo if
} // fin del primer if
} // fin del ciclo while
}
/***********************************************************
// esta llamada imprime en la LCD los estados de conectado
// y desconectado del USB dependiendo de la bandera
// estado_usb
//**********************************************************/
void mostrar_estado_usb(){
lcd_gotoxy(10,2);
if(usb_attached()){
lcd_putc(" USB:On");
}else{
lcd_putc("USB:Off");
}
// delay_ms(500);
}
//------------------------------------------------------------------
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 127
10
4
10
5
10
6
10
7
10
8
10
9
11
0
11
1
11
2
11
3
11
4
11
5
-----------------------
// cumple la funcin de configurar el bit ADFM para hacer
// la justificacin, tambin se incluye el retardo por hardware de
Tacq
// datos de entrada: bandera de justificacin
// datos de salida: nada
//------------------------------------------------------------------
-----------------------
void config_adcon2(short justificacion){
setup_adc(ADC_CLOCK_DIV_64 ); // reloj de conversin = Fosc / 64
if(justificacion){
#asm
bsf 0xFC0,7 // ADFM <- 1
#endasm
}
else{
#asm
bcf 0xFC0,7 // ADFM <- 0
#endasm
}
#asm // configura Tacq = 2Tad
bsf 0xFC0,3
bcf 0xFC0,4
bcf 0xFC0,5
#endasm
set_adc_channel(0);
}
la resolucin del CAD es a 8 bits y aunque el paquete de datos es de 1 byte, se debe
declarar las variables como tipo array:


int enva[1];
int recibe[1];


porque sino no les funcionar (comprobado)
del resto todo es igual como en el ejemplo mencionado anteriormente.
el programa del lado del HOST:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
' programa para explotar el uso del picturebox realizando graficas
en
' tiempo de ejecucion.
' para una aplicacion practica se recibiran paquetes de 1 bytes
' del dispositivo (18F4550) con el resultado del CAD a 8 bits y se
mostrara
' la onda en el picturebox
'
'
' la parte del codigo de transferencia de datos por USB, pertenece
a Slalen
'
' Saludos a foro TodoPic http://www.todopic.com.ar/foros/index.php
'
' por: Pedro - PalitroqueZ 10-Mar-2007 Hora: 09:34 PM
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 128
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76

Option Explicit

Dim cx As Integer, cy As Integer
Dim cx1 As Integer, cy1 As Integer
Dim i As Integer, j As Long
Dim x As Long, y As Integer
Dim dato(1000) As Long
Dim pcx As Long, pcy As Long
Dim fcx As Long, fcy As Long
Dim n As Integer ' n define la base de tiempo o time-division

Dim Send_Buf(0) As Byte
Const verde = &HFF00&
Const rojo = &HFF&

Dim valor As Single, maximo As Integer
Dim te As Byte

Private Sub Form_Load()
valor = 0 'VScroll1.Value
' el resultado del CAD en un tiempo discreto
maximo = 255 'VScroll1.Max
' viene siendo el maximo numero de pasos del CAD (8 bits=255,
10 bits=1023)
n = 30
' wl time-division
cy = Picture1.ScaleHeight ' 117
cx = Picture1.ScaleWidth ' 253

cy1 = Picture1.ScaleHeight ' 117
cx1 = Picture1.ScaleWidth ' 253

pcx = Picture1.Width
pcy = Picture1.Height

fcx = Me.Width
fcy = Me.Height

ajustar_tiempo (n)

Timer1.Enabled = False
Timer2.Enabled = False
Timer3.Interval = 50
Timer3.Enabled = True
'Timer3.Enabled = False

HScroll1.Value = n
End Sub

Private Sub Form_Resize()
Timer1.Enabled = False
Timer2.Enabled = False

Picture1.Height = Form1.Height / (fcy / pcy)
Picture1.Width = Form1.Width / (fcx / pcx)

Picture1.ScaleHeight = Picture1.Height / (pcy / cy1)
Picture1.ScaleWidth = Picture1.Width / (pcx / cx1)
cy = Picture1.ScaleHeight
cx = Picture1.ScaleWidth
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 129
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
Picture1.Cls
x = -1: y = 0: i = 0: j = -1
ajustar_tiempo (n)
Timer1.Enabled = True

End Sub

Private Sub Form_Unload(Cancel As Integer)

CloseMPUSBDevice 'cierra comunicaciones

End Sub

Private Sub HScroll1_Change()
n = HScroll1.Value
lblconta.Caption = n
Form_Resize
End Sub

Private Sub HScroll1_Scroll()
lblconta.Caption = HScroll1.Value
End Sub

Private Sub Timer1_Timer()
Label1.Caption = VScroll1.Value

dato(i + 1) = Int(cy - valor * (cy / maximo))
If Not j > (cx - n) Then ' pregunta si i no ha llegado a cx
Picture1.Line (x, dato(i))-(j, dato(i + 1)), vbBlack
x = j
i = i + 1
j = j + n
Else
Timer1.Enabled = False ' ya llego, deja de dibujar
Timer2.Enabled = True '
End If
Label1.Caption = "CAD= " & Round(valor * (5 / maximo), 3) & " volts
-> 0x" & Hex(valor)
End Sub

Private Sub Timer2_Timer()
Picture1.Cls
x = -1
j = -1

Label1.Caption = VScroll1.Value
'valor = VScroll1.Value
If n > 1 Then
dato(Int((cx / n) + 2)) = Int(cy - valor * (cy / maximo))
Else
dato(Int((cx / n)) + 1) = Int(cy - valor * (cy / maximo))

End If
For i = 0 To cx ' pregunta si i no ha llegado a cx
Picture1.Line (x, dato(i))-(j, dato(i + 1)), vbBlack
x = j
j = j + n ' para lograr el ajuste time-division
dato(i) = dato(i + 1) ' rellenar el dato(n) : 0 < n < cx
Next i
Label1.Caption = "CAD= " & Round(valor * (5 / maximo), 3) & "
volts -> 0x" & Hex(valor)
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 130
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
End Sub

Function ajustar_tiempo(time_division As Integer)
If time_division > 1 Then
Timer1.Interval = 3 * time_division
Timer2.Interval = 3 * time_division
Else
Timer1.Interval = 1
Timer2.Interval = 1
End If
End Function

Private Sub Timer3_Timer()
Send_Buf(0) = Asc("a")

OpenMPUSBDevice 'abre el pipe (si se puede)

If (myOutPipe <> INVALID_HANDLE_VALUE) And (myInPipe <>
INVALID_HANDLE_VALUE) Then
shpestado.FillColor = verde
Else
shpestado.FillColor = rojo
End If

Send Send_Buf, 1
recibir (te)

If rec = 0 Then
valor = 1 ' para ajustar el grfico
Else
valor = rec
End If

CloseMPUSBDevice 'cierra comunicaciones

End Sub
Private Sub cmdayuda_Click()
Dim mensaje As String

mensaje = "Este programa recoge los datos enviado desde un" &
vbCrLf
mensaje = mensaje & "dispositivo (PIC18F4550) y grafica la seal
correspondiente" & vbCrLf
mensaje = mensaje & "al resultado de una conversion analogica-
digital" & vbCrLf
mensaje = mensaje & "a 8 bits de resolucin"

MsgBox mensaje, vbInformation, "Informacion"

End Sub
el Timer3_Timer() es primordial, porque cumple triple propsito:


enva el dato de confirmacin (el ECO).
recibe el dato del dispositivo.
sensa el estado de conexin del dispositivo, ya que ante cada ejecucin y transferencia
abre y cierra el pipe.

[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 131

un ventanazo en accin:

ventana del programa final
http://www.youtube.com/watch?v=l9AdEIxAzgo
en el video, se hizo ensayos variando un potencimetro, y reconectando el dispositivo, y
TODO VA DE LUJO!
en base a mis experiencias, debo decir que trabajar con mpusbapi.dll como que es la
mejor opcin, mucho mas rpido y prctico (conociendo la programacin). pero para no
subestimar a la clase CDC, entonces:
- de acuerdo a la situacin dada, se debe escoger que es conveniente: CDC
mpusbapi.dll
- eso depender del programador que tendr que decidir cul es mejor.
como dira Neo: todo es cuestin de eleccin (tomado de la pelcula Matrix,
Revolutions)
y este fue el estudio realizado al mdulo USB si se quiere decir por encima ya que
queda mucha informacin a nivel de capas inferiores por estudiar.

[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 132
Agradecimientos y Mritos
Agradecimiento especial a los integrantes del foro TodoPic por su colaboracin y
expongo los links mas relevantes que me sirvieron de gua para la creacin de esta
bitcora.
Foro Todopic
Diego (RedPic) en PicMana
Jaime (J1M) en hobbypic.com
Microchip
Manolo Nocturno con la Wikipic
Sisco por su software WinPic800
Guillermos (Slalen) en Electronics Strange World



[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010


w w w . u n p o c o d e l e c t r o n i c a . n e t a u . n e t

Pgina 133













www.unpocodelectronica.netau.net





Tutorial de origen: http://www.unpocodelectronica.netau.net/mis-primeros-pasos-con-el-
18f4550
Versin: 1.00
Portado a PDF: Meta
http://electronica-pic.blogspot.com

También podría gustarte