Documentos de Académico
Documentos de Profesional
Documentos de Cultura
Pic 18F4550 PDF
Pic 18F4550 PDF
www.unpocodelectronica.netau.net
Introducción
Etapa Osciladora
Conociendo el PiN1 MCLR
PORTx vs LATx
Módulo CAD o ADC (I)
Módulo CAD o ADC (II)
Primera Práctica: PiCUSB
USB CDC (I)
USB CDC (II)
Monitorear el puerto COM virtual
Detectando el HOST (I)
Detectando el HOST (II)
Primera Aplicación CDC
Conociendo al SnoopyPRO
mpusbapi.dll (I)
mpusbapi.dll (II)
mpusbapi.dll (III)
mpusbapi.dll (parte 4)
mpusbapi.dll (parte 5)
mpusbapi.dll (Primera Aplicación)
Agradecimientos y Méritos Correspondientes
www.unpocodelectronica.netau.net Página 2
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010
Introducción:
Mis Primeros pasos son una serie de artículos que describen la introducción al mundo
de los uC-PIC 18F de Microchip, a través 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, características y módulos que ofrece la serie 18F.
como nota adicional, quisiera decir que esta serie de artículos de mis primeros pasos
con el 18F4550, fué escrita hace mas de 2 años 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 artículos desde su origen, ya que la intención
es mirar con la perspectiva de un novato la introducción a los 18F tal como yo lo hice
cuando tuve en mis manos el primer 18F.
el enfoque de estos artículos, fué usando una redacción un poco coloquial, mis excusas
para aquellos que sientan que no hay una redacción propia de un artículo.
Lo primero que hice fue adaptar mi programador para este PIC, mi programador es por
puerto paralelo y lo use en conjunción 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 señor,
respecto al anterior 16F877 (del cual vengo) y ¡uff! si que trae una montaña de
características (features), en la página 4 de 39632c.pdf aparece el diagrama de los pines
www.unpocodelectronica.netau.net Página 3
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010
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 ubicación del pin vdd, vss, mclr entre otros)
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 máximo!
según la elección 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
www.unpocodelectronica.netau.net Página 4
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010
esto es necesario porque lo primero que debemos tomar en cuenta son los fuses que se
van a usar y la configuración del oscilador forma parte de ello
1
...
2
//configure a 20MHz crystal to operate at 48MHz
3
#fuses
4
HSPLL,NOWDT,NOPROTECT,NOLVP,NODEBUG,USBDIV,PLL5,CPUDIV1,VREGEN
5
#use delay(clock=48000000)
6
...
www.unpocodelectronica.netau.net Página 5
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010
esto hay que analizarlo, hay algunos conocidos y otros nuevos (que se van a explicar),
así que vayamos a la página 288 de la datasheet y al archivo cabecera 18F4550.h
MCLR: significa que el pin 1 cumplirá la función 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 código es
irrelevante, ya que no usaremos el módulo 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
VREGEN: habilita el regulador de 3.3 volts que usa el módulo USB, no lo usaremos
por los momentos, se cambiará por NOVREGEN
existen mas fuses para configurar, y habría que determinar como el compilador
configura el resto
1
#fuses
2
XTPLL,MCLR,NOWDT,NOPROTECT,NOLVP,NODEBUG,USBDIV,PLL1,CPUDIV1,NOVREGEN
ahora viene escribir un código 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
¿¡Cómo!?, ¿el portb tiene funciones de entrada analógica?, pues sip, así que también
hay que meter esa opción 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
www.unpocodelectronica.netau.net Página 6
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010
vamos a escribir este código 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 todavía no trae el 18F4550
1
2
3
4
5
6
// código ejemplo para hacer funcionar por primera vez al PIC18F4550
7
mediante encendido
8
// y apagado de 8 led´s conectado al PORTB en intervalos de 1 Seg
9
// 16-Dic-2006
1
0
#include <18f4550.h> //archivo de cabecera
1
#fuses
1
XTPLL,MCLR,NOWDT,NOPROTECT,NOLVP,NODEBUG,USBDIV,PLL1,CPUDIV1,NOVREGE
1
N
2
// el fuse que configuramos anteriormente
1
#use delay(clock=48000000)
3
// el clock que tendremos a la entrada del CPU
1
4
void main() {
1
set_tris_a(0x0); // configura los puertos como salidas
5
set_tris_b(0x0);
1
set_tris_c(0x0);
6
set_tris_d(0x0);
1
set_tris_e(0x0);
7
//----------------------------------
1
disable_interrupts(global);
8
disable_interrupts(int_timer1);
1
disable_interrupts(int_rda);
9
disable_interrupts(int_ext);
2
disable_interrupts(int_ext1);
0
disable_interrupts(int_ext2);
2
setup_adc_ports(NO_ANALOGS);
1
setup_adc(ADC_OFF);
2
setup_spi(FALSE);
2
setup_psp(PSP_DISABLED);
2
setup_comparator(NC_NC_NC_NC);
3
setup_vref(FALSE);
2
port_b_pullups(FALSE);
4
//---------------------------
2
output_a (0); // saca un nivel bajo de salida en los puertos
5
output_c (0);
2
output_d (0);
6
output_e (0);
2
while(1){
7
output_b (0); // saca un nivel bajo en el portb
2
delay_ms(1000); // retardo de 1 Seg
8
output_b (0xff); // saca un nivel alto en el portb
2
delay_ms(1000); // retardo de 1 Seg
9
}
3
}
0
3
1
3
2
www.unpocodelectronica.netau.net Página 7
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010
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 están delimitadas, las saqué del código _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 están en el PORTB, para este PIC hay
que averiguar como están configurados por defectos cada pin y allí veremos si hace falta
habilitar ó deshabilitar ciertos modulos (esto se aplica también 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 configuración porque el winpic800
nos lo dirá, pero en el caso de los módulos 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)
www.unpocodelectronica.netau.net Página 8
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010
que bien nos compiló exitosamente, vamos a cargar el MPLAB-SIM y abrimos también
la ventana de los SFR, para ir viendo como están 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
código que estamos probando y después configuran la frecuencia del CPU (los fuses no
hacen falta configurarlo, porque el MPLAB los carga del que ya habíamos programado)
¡epa! aquí dice que el portb tiene algunas entradas analógicas, vamos a ver que dice el
temp18.lst (el listado que genera el compilador)
Configuration Fuses:
1
Word 1: 0220 XTPLL NOIESO NOFCMEN PLL1 CPUDIV1 USBDIV
2
Word 2: 1E1E BROWNOUT NOWDT BORV20 PUT WDT32768 NOVREGEN
3
RESERVED
4
Word 3: 8300 PBADEN CCP2C1 MCLR NOLPT1OSC RESERVED
5
Word 4: 0081 STVREN NODEBUG NOLVP NOXINST NOICPRT RESERVED
6
Word 5: C00F NOPROTECT NOCPD NOCPB
7
Word 6: E00F NOWRT NOWRTD NOWRTC NOWRTB
8
Word 7: 400F NOEBTR NOEBTRB
el fuses quedará:
1 #fuses
2 XTPLL,MCLR,NOWDT,NOPROTECT,NOLVP,NODEBUG,USBDIV,PLL1,CPUDIV1,NOVREGEN
,NOPBADEN
www.unpocodelectronica.netau.net Página 9
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010
Si por ejemplo simulamos con la opción PBADEN, verán como en el portb no habrá
problemas, hará lo que el código 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., verán que cambiarán de estado:
Simulación Mplab
www.unpocodelectronica.netau.net Página 10
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010
Tiempo en Mplab-SIM
en la ventana stopwatch, se observa que por cada línea ejecutada ocurren mas de un
ciclo de reloj, esto es típico del C, si queremos ver que ocurre en cada ciclo, nada mas
carguemos Disassembly Lisa y veremos el código en C con su correspondiente asm
Listado en Ensamblador
www.unpocodelectronica.netau.net Página 11
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010
-Que si funciona y realmente nos llena de alegría y podemos dar el siguiente paso
la segunda opción 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 tensión,
posición de los pines, etc.
http://www.youtube.com/watch?v=Wlpz-R9b0pY
www.unpocodelectronica.netau.net Página 12
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010
donde busquen en la datasheet el MCLR, verán que hay una opción 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 instrucción existe (se llama RESET)
si ven en la Pág. 126 verán 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).
otro detalle, leyendo la configuración 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 módulos ( ver Pág. 119)
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]
www.unpocodelectronica.netau.net Página 13
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010
9 XTPLL,NOMCLR,NOWDT,NOPROTECT,NOLVP,NODEBUG,USBDIV,PLL1,CPUDIV1,NOVRE
1 GEN,NOPBADEN
0 #use delay(clock=48000000) // el clock que tendremos a la entrada
1 del CPU
1
1 void main() {
2 set_tris_a(0x0); // configura los puertos como salidas
1 set_tris_b(0x0);
3 set_tris_c(0x0);
1 set_tris_d(0x0);
4 // set_tris_e(7); // RE3 <- entrada no hace falta configurarlo
1 (ver note1 pag126)
5 //-----------------------------------
1 disable_interrupts(global);
6 disable_interrupts(int_timer1);
1 disable_interrupts(int_rda);
7 disable_interrupts(int_ext);
1 disable_interrupts(int_ext1);
8 disable_interrupts(int_ext2);
1 setup_adc_ports(NO_ANALOGS);
9 setup_adc(ADC_OFF);
2 setup_spi(FALSE);
0 setup_psp(PSP_DISABLED);
2 setup_comparator(NC_NC_NC_NC);
1 setup_vref(FALSE);
2 //-------------------------------------------
2 port_b_pullups(FALSE);
2 output_a (0); // saca un nivel bajo de salida en los puertos
3 output_b (0); // saca un nivel bajo en el portb
2 output_c (0);
4 output_d (0);
2 output_e (0);
5 while(1){
2 if(input_state(PIN_E3)){
6 output_b (0); // saca un nivel bajo en el portb
2 delay_ms(1000); // retardo de 1 Seg
7 output_b (0xff); // saca un nivel alto en el portb
2 delay_ms(1000);
8 }
2 else{
9 output_b (0); // saca un nivel bajo en el portb
3 output_c (0); // saca un nivel bajo en el portc
0 delay_ms(1000);
3 output_c (0xff); //saca un nivel alto en portc
1 delay_ms(1000);
3 }
2 }
3 }
3
3
4
3
5
3
6
3
7
3
8
3
9
www.unpocodelectronica.netau.net Página 14
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010
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 (según el MPLAB el módulo 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
después de compilar exitosamente (gracias Dios, jeje) y verificar los fuses veremos en la
simulación en MPLAB a ver que pinta tiene:
http://www.youtube.com/watch?v=anfwe__gnYc
www.unpocodelectronica.netau.net Página 15
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010
nota: el circuito para este ejemplo está en el adjunto, en el circuito del ejemplo1 omití
un componente que había 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
PORTx vs LATx
www.unpocodelectronica.netau.net Página 16
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010
la diferencia principal que se ve allí es el buffer RD LAT cuya función es leer el estado
de la salida del LAT (¿que función 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 erróneas en la familia 16F manejando bit´s se
recomienda colocar un nop entre pines:
1 bsf porta,0
2 nop
3 bsf porta,1
obviamente que la existencia del registro LATx es una mejora ya que en un ciclo de
instrucción garantizas la escritura en un pin del puerto, pero esto habría que
comprobarlo con un ejemplo
1 #asm
2 bsf PORTB,0,1
3 bsf PORTB,1,1
4 #endasm
www.unpocodelectronica.netau.net Página 17
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010
pero sospecho que el pcwh, mete sus narices aún en asm, porque en la ayuda del ccs,
dice:
BSF f,b
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.
una nota curiosa vean la dirección señalada (viendo el listado en asm generado por el
CCS del ejemplo2)
Coincidencia
www.unpocodelectronica.netau.net Página 18
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010
así será de fea la programación 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, configuratión bits. (ver
Pag . 287)
aquí hay que escribirlos toditos, porque no se sabe como estan por defectos, pero sin
complicar mucho la explicación lo que se hizo fué ver como el CCS configuraba los 7
word y llevarlos al asm, y eso fué lo que está arriba.
para la escritura del PORTB, primero se utilizará el clásico PORTB, a ver que sucede y
después el LATB
www.unpocodelectronica.netau.net Página 19
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010
21 goto inicio
22 ; org 0x8 interrup alta priori
23 ; org 0x18 baja prioridad
24 inicio:
25 ; clrf LATA ; limpia los latch
26 ; clrf LATB
27 ; clrf LATC
28 ; clrf LATD
29 ; clrf LATE
30 clrf TRISA ; configuar el port como salida ¡que bueno!, no hay
31 que estar cambiando de bancos ;-)
32 movlw 0x1
33 movwf TRISB ; configura RB0<- entrada, el resto -> salida
34 clrf TRISC
35 clrf TRISD
36 clrf TRISE
37 ;//------------------------------------------------------
38 ; ahora viene la deshabilitación de modulos (pheriperals)
39 ;*******************************************************
40 clrf,ADCON0 ; desactiva el CAD
41 movlw 0xf
42 movwf ADCON1 ; todas digitales
43 bcf INTCON,GIE ; desactiva interrupciones
44 movlw 0x7
45 movwf CMCON ;desactiva el modulo comparador
46 ;clrf CVRCON ; desactiva el Vref del comparador no hace falta
47 clrf SPPCON ; desactiva el modulo Streaming Parallel Port (SPP)
48 clrf SSPCON1 ; desactiva el modulo MSSP,SSPEN
49 bcf UCON,USBEN ; desactiva el modulo USB
50 bsf INTCON2,RBPU ; desactiva las resistencias de amarre en PORTB
51 ;//-------------------------------------------
52 ciclo:
53 btfss PORTB,0
54 bra LED_RB2
55 bcf PORTB,2,1
56 bcf PORTB,4,1
57 bcf PORTB,6,1
58
59 bsf PORTB,1,1
60 bsf PORTB,3,1
61 bsf PORTB,5,1
62 bsf PORTB,7,1
63 bra ciclo
64 LED_RB2:
65 bcf PORTB,1,1
66 bcf PORTB,3,1
67 bcf PORTB,5,1
68 bcf PORTB,7,1
69
bsf PORTB,2,1
bsf PORTB,4,1
bsf PORTB,6,1
bra ciclo
end
como pueden ver, en este código se va a comprobar que pasa si usamos la instrucción
PORTB para manejar datos de salida y LATx
notas:
-por darmelas de vivo, traté de configurar el TRISB, así:
www.unpocodelectronica.netau.net Página 20
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010
movff 0×1,TRISB
pero no sirve, porque para esa instrucción 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 instrucción nueva el BRA, suena al salto que se utiliza en BASIC (que sería
BRANCH) y ¿porque no usamos el goto? bueno también sirve, una diferencia que leí,
es que el goto puede saltar mas lejos, para nuestro ejemplo el BRA sirve, lo dejaremos.
http://www.youtube.com/watch?v=uhYkxjsU6wU
el warning se debe a que la instrucción limpia un registro de solo 6 bits, los menos
significativos, pero no hay rollo.
en la simulación vemos que ningún pin del puertoB cambia, ni el LATB, pero como yo
soy necio, voy a grabar ese mismo código en el pic, haber que hace.
el video en protoboard:
http://www.youtube.com/watch?v=tAMmVcAKKGk
¡Qué! ¿y porque se quedan prendidos esos 3? vamonos a revisar el código, 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 0004 6A92 CLRF 0xf92, ACCESS 29: clrf
3 TRISA ; configuar el port como salida ¡que bueno!, no hay que
4 estar cambiando de bancos ;-)
5 0006 0E01 MOVLW 0x1 30: movlw 0x1
6 0008 6E93 MOVWF 0xf93, ACCESS 31: movwf
7 TRISB ; configura RB0<- entrada, el resto -> salida
8 000A 6A94 CLRF 0xf94, ACCESS 32: clrf
9 TRISC
10 000C 6A95 CLRF 0xf95, ACCESS 33: clrf
11 TRISD
12 000E 6A96 CLRF 0xf96, ACCESS 34: clrf
13 TRISE
14 35: ;//--------
15 ----------------------------------------------
www.unpocodelectronica.netau.net Página 21
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010
16 36: ; ahora
17 viene la deshabilitación de modulos (pheriperals)
18 37:
19 ;*******************************************************
20 0010 6A00 CLRF 0, ACCESS 38:
21 clrf,ADCON0 ; desactiva el CAD
22 0012 0E0F MOVLW 0xf 39: movlw 0xf
23 0014 6EC1 MOVWF 0xfc1, ACCESS 40: movwf
24 ADCON1 ; todas digitales
25 0016 9EF2 BCF 0xff2, 0x7, ACCESS 41: bcf
26 INTCON,GIE ; desactiva interrupciones
27 0018 0E07 MOVLW 0x7 42: movlw 0x7
28 001A 6EB4 MOVWF 0xfb4, ACCESS 43: movwf
29 CMCON ;desactiva el modulo comparador
30 44: ;clrf
31 CVRCON ; desactiva el Vref del comparador no hace falta
32 001C 6A65 CLRF 0xf65, ACCESS 45: clrf
33 SPPCON ; desactiva el modulo Streaming Parallel Port (SPP)
34 001E 6AC6 CLRF 0xfc6, ACCESS 46: clrf
35 SSPCON1 ; desactiva el modulo MSSP,SSPEN
36 0020 966D BCF 0xf6d, 0x3, ACCESS 47: bcf
37 UCON,USBEN ; desactiva el modulo USB
38 0022 8EF1 BSF 0xff1, 0x7, ACCESS 48: bsf
39 INTCON2,RBPU ; desactiva las resistencias de amarre en PORTB
40 49:
41 ;disable_interrupts(global);
42 50:
43 ;setup_adc_ports(NO_ANALOGS);
44 51:
45 ;setup_adc(ADC_OFF);
46 52:
47 ;setup_spi(FALSE);
48 53:
49 ;setup_psp(PSP_DISABLED);
50 54:
51 ;setup_comparator(NC_NC_NC_NC);
52 55:
53 ;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
www.unpocodelectronica.netau.net Página 22
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010
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
www.unpocodelectronica.netau.net Página 23
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010
mapa de la memoria
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 también): ACCESS.
Es válido si no se coloca nada, el MPLAB, lo asume como a=0 (ver pagina 67)
www.unpocodelectronica.netau.net Página 24
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010
4 pulsador en RB0
5 ; que encenderá led´s pares e impares
6 ; 21-Dic-2006
7
8 LIST P=18F4550 ;directive to define processor
9 #include <P18F4550.INC> ;processor specific variable definitions
10
11 CONFIG FOSC = XTPLL_XT, PLLDIV = 1,CPUDIV = OSC1_PLL2,USBDIV =
12 2,PWRT = ON,BOR = ON, VREGEN = OFF
13 CONFIG WDT = OFF ,WDTPS = 1,MCLRE = ON,PBADEN = OFF,LVP = OFF,XINST
14 = OFF,DEBUG = OFF
15
16 CBLOCK 0x0
17
18 ENDC
19
20 org 0
21 goto inicio
22 ; org 0x8 interrup alta priori
23 ; org 0x18 baja prioridad
24 inicio:
25 ; clrf LATA ; limpia los latch
26 ; clrf LATB
27 ; clrf LATC
28 ; clrf LATD
29 ; clrf LATE
30 clrf TRISA ; configuar el port como salida ¡que bueno!, no hay
31 que estar cambiando de bancos ;-)
32 movlw 0x1
33 movwf TRISB ; configura RB0<- entrada, el resto -> salida
34 clrf TRISC
35 clrf TRISD
36 clrf TRISE
37 ;//------------------------------------------------------
38 ; ahora viene la deshabilitación de modulos (pheriperals)
39 ;*******************************************************
40 clrf,ADCON0 ; desactiva el CAD
41 movlw 0xf
42 movwf ADCON1 ; todas digitales
43 bcf INTCON,GIE ; desactiva interrupciones
44 movlw 0x7
45 movwf CMCON ;desactiva el modulo comparador
46 ;clrf CVRCON ; desactiva el Vref del comparador no hace falta
47 clrf SPPCON ; desactiva el modulo Streaming Parallel Port (SPP)
48 clrf SSPCON1 ; desactiva el modulo MSSP,SSPEN
49 bcf UCON,USBEN ; desactiva el modulo USB
50 bsf INTCON2,RBPU ; desactiva las resistencias de amarre en PORTB
51 ciclo:
52 btfss PORTB,0
53 bra LED_RB2
54 bcf PORTB,2,0
55 bcf PORTB,4,0
56 bcf PORTB,6,0
57
58 bsf PORTB,1,0
59 bsf PORTB,3,0
60 bsf PORTB,5,0
61 bsf PORTB,7,0
62 bra ciclo
63 LED_RB2:
64 bcf PORTB,1,0
www.unpocodelectronica.netau.net Página 25
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010
65 bcf PORTB,3,0
66 bcf PORTB,5,0
67 bcf PORTB,7,0
68
bsf PORTB,2,0
bsf PORTB,4,0
bsf PORTB,6,0
bra ciclo
end
http://www.youtube.com/watch?v=m-7uVP1ji6w
allí muestra que el PORTB cambia los estados de acuerdo a la programación 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 led´s 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).
www.unpocodelectronica.netau.net Página 26
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010
www.unpocodelectronica.netau.net Página 27
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010
9 end
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
www.unpocodelectronica.netau.net Página 28
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010
8
0
8
1
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
www.unpocodelectronica.netau.net Página 29
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010
-Conceptos
nos vamos directo para la página 261 del 39632c.pdf, que es el datasheet del la familia
PIC18F2455/2550/4455/4550 y allí está un capítulo dedicado a este módulo.
-las diferencias que leí respecto al 16F877, le agregaron un adcon2 y hay 13 posibles
entradas analógicas multiplexadas.
-Le agregaron unos bits que son muy interesantes ACQT2:ACQT0 para manejar el
tiempo de adquisición, ya lo explicaremos.
Quisiera hacer un resumen del funcionamiento del CAD para poder explicar las nuevas
opciones que trae el 18F4550 y las mejoras respecto al 16F877
www.unpocodelectronica.netau.net Página 30
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010
-existen unos pines que se pueden configurar como entrada analógica, del cual se toma
uno a la vez.
-dado un arreglo R-C,que existe dentro, o a la entrada del módulo CAD se toma un
nivel de tensión en un tiempo discreto, ese voltaje se almacenará en el condensador
interno (Chold)
www.unpocodelectronica.netau.net Página 31
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010
esto aparece en la página 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:
www.unpocodelectronica.netau.net Página 32
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010
-en este proceso de conversión hay otros parámetros, uno de ellos es el reloj de
conversión,
esto quiere decir que el módulo CAD, trabaja con un reloj distinto del CPU y que puede
depender o no de éste. Eso lo dirá la debida configuración 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 aplicación sería poner a dormir el PIC mientras se
está haciendo una conversión, ¿y que utilidad puede tener esto?, bueno al estar
trabajando solo el módulo CAD, se reduce el ruido de conmutación de los otros
periféricos y puede aumentar la precisión del valor digital obtenido.
Desventajas: usando el oscilador interno se tarda mas la conversión (en el orden de los
mS, que podría sería mucho tiempo para algunos eventos)
esto también tiene su tiempo y es el tiempo (retardo) de conversión analógico digital por
bit, llamado Tad. Según la pagina 267 se requiere de un tiempo de 11Tad para realizar
una conversión, el Tad mínimo para el CAD del 18F4550 es 700nS(pagina 400)
pero haciendo algunos cálculos de acuerdo a la tabla 21-1
www.unpocodelectronica.netau.net Página 33
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010
www.unpocodelectronica.netau.net Página 34
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010
desde luego que todo esto es pura teoría, así que vamos a darle con un ejemplo
-usaremos el Tacq por hardware, así que si nuestro Tad= 1.33uS, entonces usando un
tacq= 2Tad= 2*1.33uS = 2.66uS
www.unpocodelectronica.netau.net Página 35
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010
www.unpocodelectronica.netau.net Página 36
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010
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 demás constantes dentro de la
función setup_adc().
int ADC_ACQT_2TAD=0×1;
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 línea setup_adc(ADC_CLOCK_DIV_64 ||
ADC_ACQT_2TAD ); por:
1 #asm
2 movlw 0b10001110 ;justificacion_derecha,2Tad,Fosc/64
3 movwf 0xFC0 ; direccion de ADCON2
4 #endasm
www.unpocodelectronica.netau.net Página 37
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010
http://www.youtube.com/watch?v=Fzf2_wvbiQU
el estímulo no está funcionando, de verdad que pasé un rato creyendo que estaba mal
configurado el Register Injection, pero después me di cuenta que faltaba la instrucción
setup_adc(), si así como lo leen, ¿como se hace entonces si lo había quitado?, bueno, lo
coloque de nuevo y le añadí el pedacito en assembler para que aceptara el cambio en
ADCON2
claro, que cambié el movwf por iorwf, para que me aceptara los nuevos bits sin alterar
el estado anterior de ADCON2,
también es bueno decir que por aquí se puede cambiar la justificación, hay otra cosa
interesante, en CCS hay una directiva #DEVICE ADC=xx , sería bueno analizar que
pasa si cambio ADC=10 por ADC=16, ¿esto hará la justificación hacia la izquierda?,
sería otro estudio.
1A0
2AA
3FF
www.unpocodelectronica.netau.net Página 38
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010
http://www.youtube.com/watch?v=H4ozbfY1PGY
Lo importante es que hicimos arrancar el módulo 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
www.unpocodelectronica.netau.net Página 39
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010
cuando intentas medir niveles cercano a 0 volts usando el TL082. Buscando por ahí
conseguí una página donde explican el fenómeno (llamado latch-up), a mi me sucede
esto porque alimento al operacional con +Vcc=+5 y -Vcc=0.
según estos datos obtenidos, la precisión 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 máximo permitido por ADCON2, esto es 20Tad = 20 * 1.33uS =
26.6 uS bastante tiempo de sobra que sumándole 11Tad = 11* 1.33uS =14.63uS daría
una conversión aproximada de 41.23uS
1 #asm
2 movlw 0b10111110 ;justificacion_derecha,20Tad,Fosc/64
3 iorwf 0xFC0,1 ; direccion de ADCON2
4 #endasm
www.unpocodelectronica.netau.net Página 40
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010
Conclusión:
Bueno señores, esos resultados como que mejoraron un poco, uhmmmm… la verdad es
que nunca he podido obtener valores calculados en la práctica, quizás un montaje mejor
elaborado en baquelita y bien filtrado pueda aumentar la precisión.
espero que les pueda instruir en algo.
Continuando con el CAD, seguí haciendo varias mediciones con el código realizado
anteriormente y descubrí nuevos detalles
-para la alimentación en AN0, usé un 7805 aparte, para separar los voltajes.
-noté una variación de Vdd, no se porque la alimentación del 7805 cambia cuando varío
el potenciómetro 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.
www.unpocodelectronica.netau.net Página 41
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010
nuevos datos
según la gráfica se nota una mejoría en la precisión, pero yo sigo obstinado a conseguir
mas precisión, después de un buen rato debugeando con el MPLAB SIM, observé la
pestaña MPLAB SIM que está adentro de la ventana OUTPUT y me salía este mensaje:
-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 regaño, muy cierto me salté esos
tiempos:
www.unpocodelectronica.netau.net Página 42
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010
3Tad = 3*(64/48MHZ)=3.99uS
yo con mi manía lo saqué para ambos valores(2Tad y 3Tad) y aquí estan los resultados:
www.unpocodelectronica.netau.net Página 43
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010
www.unpocodelectronica.netau.net Página 44
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010
¡¡¡Ahhh!!! se dan cuenta señoras y señores, los valores son cercanos a lo calculado, o
sea, que ese tiempito entre conversión y conversión 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 iniciación con el 18F4550, formaría parte de la configuración
básica de un módulo CAD.
-observen en los resultados que la variación de Vdd fué muy poca !?!?
voy a modificarlo como quería en un principio, tratar que el CAD se tarde lo mínimo en
hacer una conversión, es decir, con Tacq=2Tad y un 2Tad entre muestras, para ellos
cambiamos por estas lineas:
1 #asm
2 movlw 0b10001110 //justificacion_derecha,2Tad,Fosc/64
3 ...
4 ...
5 delay_us(3); // para pasar >= 2Tad a la sig CAD
6 ...
www.unpocodelectronica.netau.net Página 45
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010
-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 led´s se encendian, Vdd iba
disminuyendo, esto no tiene que ver con la configuración del CAD.
-que hay que estar pendiente con los minimos detalles que dicen en la datasheet, tal es el
caso del mínimo Tad entre muestras.
www.unpocodelectronica.netau.net Página 46
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010
Ahora vamos a hablar del módulo 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 led´s. Así que voy a describir esta pequeña
aventura, como para la bajar la “fiebre” un poco.
- allí hay un pdf donde aparece el circuito eléctrico, para el 18F2550, bueno yo estoy
usando el 18F4550 y sirve también. solo hay que cambiar el encabezado por #include
<18F4550.h>
- usar un software para enviar los comandos que activaran los led´s, yo aún no tengo el
visual C#, pero ya que el amigo Diego RedPic realizó uno que es compatible con el
mismo código, lo usé y se llama PicUSBDelphi.exe (forma parte del archivo
PicUSBDelphi.zip que se baja desde la página picmania.garcia-
cuervo.net/usb_0_desencadenado.php).
- seguido conectar todo. Hay que revisar los contactos del conector USB. Yo usé el plug
estándar tipo A (visto de la parte de abajo)
www.unpocodelectronica.netau.net Página 47
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010
cuyos pines van así: (tomado de especificaciones USB2.0 capítulo 6 página 99)
donde:
1=Vbus
2=D-
3=D+
4=Gnd
ese plug lo conecté a una extensión, por si acaso medí la tensión de Bus=5.1 volts.
el windows me detectó un nuevo dispositivo USB, hay que elegir la carpeta donde están
los controladores que están en el mismo picusb.zip, son 4 archivitos:
www.unpocodelectronica.netau.net Página 48
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010
picusb.cat
picusb.inf
picusbci.dll
wdmstub.sys
después el windows hace todo lo que tiene que hacer (configurar dispositivo, etc.)
http://www.youtube.com/watch?v=XZN4L9kimr0
www.unpocodelectronica.netau.net Página 49
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010
Aquí hay otro ejemplito para ir aprendiendo y practicando con el módulo USB que trae
el 18F4550, esta vez se va a utilizar la clase CDC ó Communications Devices Class,
entrando un poquito en teoría, se puede decir que una clase USB es un grupo de
dispositivos (o interfaces dentro de un dispositivo) con ciertas características en común.
Típicamente, 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 función(ó dispositivo) comunicarse con el
COM virtual a través del controlador HOST de USB en la computadora.
nota: este tema sobre la teoría y funcionamiento del bus USB no es para digerirlo a la
primera leída, pues también hay que estudiarlo al nivel del módulo que trae el PIC
www.unpocodelectronica.netau.net Página 50
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010
como verán hay 2 botones cada uno para enviar la orden al PIC y después éste, nos
envié la respectiva cadena, dicha orden será un byte ó un carácter, posteriormente esa
cadena se guardará en la caja de texto.
www.unpocodelectronica.netau.net Página 51
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010
45
46 Private Sub MSComm1_OnComm()
47 Dim InBuff As String
48 Select Case MSComm1.CommEvent
49 Case comEvReceive
50 InBuff = MSComm1.Input
51 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 código hay varias cosas que decir, lo primordial es tener bien configurado al
MSCOMM, como por ejemplo RThreshold y para evitar caracteres extraños 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 después de ejecutar el evento comEvReceive,
entre otras cosas para limpiar el buffer, en fin es cuestión de que hagan los respectivos
ensayos de acuerdo a cada situación.
1 /* ejemplo6_parte2.c
2 este ejemplo hace uso del módulo USB en modo CDC transmitiendo
3 datos
4 hacia un puerto COMx emulado en Windows
5 adaptación del código original de RRCdcUSB de RedPic
6 Pedro-PalitroqueZ
7 12/01/07
8 */
9 #include <18F4550.h>
1 #fuses
0 XTPLL,MCLR,NOWDT,NOPROTECT,NOLVP,NODEBUG,USBDIV,PLL1,CPUDIV1,VREGEN,
1 NOPBADEN
1 #use delay(clock=48000000)
1
2 #include "usb_cdc.h"
1
3 void main() {
1 usb_cdc_init();
4 usb_init();
1 while(!usb_cdc_connected()) {}
5 // espera a detectar una transmisión de la PC (Set_Line_Coding)
1 do{
6 usb_task();
1 if (usb_enumerated()){
7 if(usb_cdc_kbhit()){ //en espera de nuevo(s) caracter(es)
1 en el buffer
8 if(usb_cdc_getc()=='x'){ //¿lo que llegó fué el caracter
1 x?
9 printf(usb_cdc_putc, "el 11111111111111111111\n\r");
2 //si, entonces envía una cadena hacia el PC
0 }
2 if(usb_cdc_getc()=='a'){ //¿lo que llegó fué el caracter
1 a?
2 printf(usb_cdc_putc, "el 22222222222222222222\n\r");
www.unpocodelectronica.netau.net Página 52
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010
allí se puede apreciar que si el byte que llega es una “x”, entonces se prepara para
transmitir ese montón de unos, y si llega una “a” manda ese montón de does
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í habría que aplicar una
validación 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 fácil y rápida de hacer comunicación con la
computadora, ya que podemos tomar programas de VB ya hechos para el MSCOMM y
que mediante una pequeña adaptación podemos transmitir por el USB. La programación
para el PIC varía ligeramente.
www.unpocodelectronica.netau.net Página 53
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010
Seguimos con el módulo USB y con la clase CDC, porque a mi pensar es una manera
fácil 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.
usb_enumerated()
usb_cdc_kbhit()
usb_cdc_getc()
usb_cdc_connected()
1 /* ejemplo6_parte3.c
2 en este ejemplo se tratará de concocer la configuración del
3 dispositivo, cuando
4 hay/no hay conexión con el PC mediante los comandos
5 usb_enumerated()
6 usb_cdc_kbhit()
7 usb_cdc_getc()
8 usb_cdc_connected()
9
1 adaptación del código original de RRCdcUSB de RedPic
0 Pedro-PalitroqueZ 14/01/07
1 */
1 #include <18F4550.h>
1 #fuses
2 XTPLL,MCLR,NOWDT,NOPROTECT,NOLVP,NODEBUG,USBDIV,PLL1,CPUDIV1,VREGEN,
1 NOPBADEN
3 #use delay(clock=48000000)
1
4 #define use_portb_lcd TRUE
1
5 #include <lcd.c>
1 #include "usb_cdc.h"
6
1 void main(){
7 usb_cdc_init(); // llamadas necesarias para iniciar el módulo USB
1 usb_init(); // llamadas necesarias para iniciar el módulo USB
8 lcd_init(); // llamadas necesarias para iniciar la LCD
1 while(!usb_cdc_connected()) {lcd_putc("\fUSB NO detectadO");
9 delay_ms(100);} // para evitarme un retardo y que no parpadee la
www.unpocodelectronica.netau.net Página 54
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010
2 LCD
0 // espera a detectar una transmisión de la PC (Set_Line_Coding)
2 lcd_putc("\fUSB DeTectAdo"); delay_ms(600);
1 do{
2 usb_task();
2 if (usb_enumerated()){
2 lcd_putc("\fya enumerado\n"); // para evitarme un retardo
3 y que no parpadee la LCD
2 lcd_putc("USB ConeCtaDo"); // para evitarme un retardo y
4 que no parpadee la LCD
2 delay_ms(800);
5 if(usb_cdc_kbhit()){ //en espera de nuevo(s) caracter(es)
2 en el buffer
6 if(usb_cdc_getc()=='a'){ //¿lo que llegó fué el caracter
2 a?
7 lcd_putc("\fdAto rEciBido\n"); // para evitarme un
2 retardo y que no parpadee la LCD
8 lcd_putc("de la PC"); // para evitarme un retardo y
2 que no parpadee la LCD
9 delay_ms(800); //tiene que ser mayor a 500mS para que
3 no existan parpadeos
0 }
3 }
1 }
3 lcd_putc("\fEn El bUClE UsB"); // para evitarme un retardo y que
2 no parpadee la LCD
3 delay_ms(700);
3 }while (TRUE); // bucle eterno
3 }
4
3
5
3
6
3
7
3
8
3
9
4
0
4
1
4
2
4
3
4
4
4
5
allí incluí una pantalla LCD, el cuál me mostrará que sucede en determinado momento
dentro del código, la idea es conocer que hace el pic cuando:
- no hay conexión
- conectado el cable USB
www.unpocodelectronica.netau.net Página 55
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010
- ejecutando la aplicación VB
- enviando el dato hacia el dispositivo
y todo eso me lo mostrará en pantalla con unos lcd_putc que coloqué en lugares
estratégicos, el código en VB lo modifiqué ligeramente, para que envíe un carácter 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:
- “USB detectado”, “ya enumerado USB conectado”, “en el bucle USB” -> sucede
cuando ejecuto la aplicación en VB
- “dato recibido de la PC” -> sucede cuando clíco en el botón „enviando a al pic‟
recomendación: pegar un switche doble para desconectar a D- D+, para no estar a cada
rato sacando la extensión y hacer una reconexión fácil.
esto está correcto solo en función del código, pues una vez que entra dentro del bucle no
sale, y siempre mostrará que está conectado aunque no sea cierto.
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
jamás el puerto a menos que reconecte el cable USB de nuevo, ¿¿??
el código en VB:
www.unpocodelectronica.netau.net Página 56
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010
12 Option Explicit
13 Dim value As Long
14 Dim bandera As Boolean
15
16
17 Private Sub Command2_Click()
18 Timer1.Enabled = False
19 If MSComm1.PortOpen = True Then
20 MSComm1.Output = "a"
21 End If
22 Timer1.Enabled = True
23 End Sub
24
25
26 Private Sub Form_Load()
27 MSComm1.CommPort = 4
28 MSComm1.OutBufferSize = 1 'tamaño del dato a transmitir
29
30 Timer1.Interval = 50
31 Timer1.Enabled = True
32 bandera = False
33 End Sub
34
35 Private Sub Form_Unload(Cancel As Integer)
36 If MSComm1.PortOpen = True Then
37 MSComm1.PortOpen = False
38 End If
39 End Sub
40
41 Private Sub Timer1_Timer()
42 On Error GoTo paca
43 DoEvents
44 If MSComm1.PortOpen = True Then
45 DoEvents
46 lblestado.Caption = "Conectado"
47 Debug.Print "Conectado"
48 MSComm1.PortOpen = False
49 Exit Sub
50 Else
51 DoEvents
52 MSComm1.PortOpen = True
53 Exit Sub
54 End If
55 paca: Debug.Print Err.Number & ": " & Err.Description
56 Select Case Err.Number
57 Case 8002 'Número de puerto no válido
58 DoEvents
59 lblestado.Caption = "Desconectado"
60 Case 8005 'el puerto ya está abierto
61 DoEvents
62 lblestado.Caption = "puerto abierto"
63 Case 8012 '8012 el dispositivo no está abierto
64 DoEvents
65 lblestado.Caption = "Desconectado"
66 Case 8015
67 DoEvents ' para evitar retardos en bucles
68 lblestado.Caption = "Desconectado"
End Select
Exit Sub
End Sub
www.unpocodelectronica.netau.net Página 57
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010
lecturas recomendadas:
AN956 Migrating Applications to USB from RS-232 UART with Minimal Impact on PC
Software
volver arriba
Probé el estado de una conexión pero solo en el software de la PC, sin enviar datos
(independiente del código que exista en el PIC, el programa verá si existe o no el
COMx). una solución que encontré fué abrir y cerrar el puerto dentro del escaneo
periódico del control timer.
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
, específicamente el error 8015: No se puede establecer el estado de comunicación;
puede que haya uno o más parámetros de comunicaciones no válidos ó 8002: Número
de puerto no válido, es allí que mediante el control de errores puedo decir que el pic está
desconectado del controlador HOST de la PC
1 Option Explicit
2
3 Private Sub Command1_Click()
4 Timer1.Enabled = False
5 If MSComm1.PortOpen = False Then
6 Exit Sub
7 Else
8 MSComm1.Output = "a"
9 End If
10 Timer1.Enabled = True
11 End Sub
12
13 Private Sub Form_Load()
14 MSComm1.CommPort = 4
15 MSComm1.OutBufferSize = 1 'tamaño del dato a transmitir
16 'MSComm1.PortOpen = True
17
18 Timer1.Interval = 50
19 Timer1.Enabled = True
20 End Sub
www.unpocodelectronica.netau.net Página 58
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010
21
22 Private Sub Form_Unload(Cancel As Integer)
23 If MSComm1.PortOpen = True Then
24 MSComm1.PortOpen = False
25 End If
26 End Sub
27
28 Private Sub Timer1_Timer()
29 Dim a As String
30 On Error GoTo paca
31 DoEvents
32 If MSComm1.PortOpen = True Then
33 DoEvents
34 lblestado.Caption = "Conectado"
35 Debug.Print "Conectado"
36 MSComm1.PortOpen = False
37 Exit Sub
38 Else
39 DoEvents
40 MSComm1.PortOpen = True
41 Exit Sub
42 End If
43 paca: Debug.Print Err.Number & ": " & Err.Description
44 Select Case Err.Number
45 Case 8002 'Número de puerto no válido
46 DoEvents
47 lblestado.Caption = "Desconectado"
48 Case 8005 'el puerto ya está abierto
49 DoEvents
50 lblestado.Caption = "puerto abierto"
51 Case 8012 '8012 el dispositivo no está abierto
52 DoEvents
53 lblestado.Caption = "Desconectado"
54 Case 8015
55 DoEvents
56 lblestado.Caption = "Desconectado"
57 End Select
58 Exit Sub
59 End Sub
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 código similar al del evento timer (para
que ocurra solo una vez) dentro del evento donde quiero enviar datos, después que
envie/reciba datos, arranco el escaneo Timer1.Enabled = True
www.unpocodelectronica.netau.net Página 59
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010
Detectando el HOST
Después de varios días de descanso y para poner a trabajar al subconsciente en esto del
USB seguimos con este módulo, y ¿porqué? es que este módulo es la joya de la corona
de este PIC, así que seguiré echándole mano hasta abarcar todo lo necesario para
realizar una comunicación PIC<->PC básica.
ya en el ejemplo anterior dimos cuenta de como detectar una conexión 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:
#include <18F4550.h>
1 #fuses
2 XTPLL,MCLR,NOWDT,NOPROTECT,NOLVP,NODEBUG,USBDIV,PLL1,CPUDIV1,VREGEN,N
3 OPBADEN
4 #use delay(clock=48000000)
5
6 #include "usb_cdc.h"
7
8 void main() {
...
#if __USB_PIC_PERIF__
#if defined(__PCM__)
1
#error CDC requires bulk mode! PIC16C7x5 does not have bulk mode
2
#else
3
#include <pic18_usb.h> //Microchip 18Fxx5x hardware layer for
4
usb.c
5
#endif
6
#else
7
#include <usbn960x.c> //National 960x hardware layer for usb.c
8
#endif
9
#include "rr2_USB_Cdc_Monitor.h" //USB Configuration and Device
10
descriptors for this UBS device
11
#include <usb.c> //handles usb setup tokens and get
descriptor reports
www.unpocodelectronica.netau.net Página 60
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010
si observamos el código del ejemplo anterior hay unas funciones de inicialización que
hay que llamar para poder empezar a transmitir datos, una de ellas es
usb_init( );
1 void usb_init(void) {
2 usb_init_cs();
3
4 do {
5 usb_task();
6 } while (usb_state != USB_STATE_POWERED);
7}
1 /*******************************************************************
2 **********
3 /* usb_task()
4 /*
5 /* Summary: Keeps an eye on the connection sense pin to determine if
6 we are
7 /* attached to a USB cable or not. If we are attached to a
8 USB cable,
9 /* initialize the USB peripheral if needed. If we are
1 disconnected
0 /* from the USB cable, disable the USB peripheral.
1 /*
1 /* NOTE: If you are not using a connection sense pin, will
1 automatically
2 /* enable the USB peripheral.
1 /*
3 /* NOTE: this enables interrupts once the USB peripheral is
1 ready
4 /*
1 /*******************************************************************
5 **********/
1 void usb_task(void) {
6 if (usb_attached()) {
1 ...
7
1 analicen lo que dice esta función, ahí se habla de un tal connection
8 sense pin que interesante, veamos que hace la función
1 usb_attached():
9 ...
2 /*******************************************************************
0 ***********
2 /* usb_attached()
1 /*
2 /* Summary: Returns TRUE if the device is attached to a USB cable
2 /*
2 /*******************************************************************
3 **********/
2 #if USB_CON_SENSE_PIN
4 #define usb_attached() input(USB_CON_SENSE_PIN)
www.unpocodelectronica.netau.net Página 61
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010
2 #else
5 #define usb_attached() TRUE
2 #endif
6 ...
2
7
2
8
2
9
3
0
3
1
3
2
uuhmmm esa función está hecha mediante definición y llama a su vez a un tal
USB_CON_SENSE_PIN
haciendo una pausa, esto que estoy haciendo es analizando el código inversamente, es
decir, mediante una simulación en el MPLAB voy observando donde cae cada llamado
para así determinar esa parte del código que me interesa.
http://www.youtube.com/watch?v=Tg_KTJ-8WfE
la línea BTFSC 0xf6d, 0×3 está preguntando si USBEN=0, mientras que para el primer
condicional no aparece su respectiva línea en asm.
ahora que recuerdo en el código que escribió el amigo J1M, aparece una descripción de
ese USB_CON_SENSE_PIN
(también aparece en el ejemplo ex_usb_serial2.c que trae el CCS)
1 ////////////////////////////////////////////////////////////////////
2 /////////
3 //
4 // If you are using a USB connection sense pin, define it here. If
5 you are
6 // not using connection sense, comment out this line. Without
7 connection
8 // sense you will not know if the device gets disconnected.
9 // (connection sense should look like this:
1 // 100k
0 // VBUS-----+----/\/\/\/\/\----- (I/O PIN ON PIC)
1 // |
1 // +----/\/\/\/\/\-----GND
1 // 100k
2 // (where VBUS is pin1 of the USB connector)
1 //
3 ////////////////////////////////////////////////////////////////////
1 /////////
4 //#define USB_CON_SENSE_PIN PIN_B2 //CCS 18F4550 development kit
www.unpocodelectronica.netau.net Página 62
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010
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, específicamente 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.
hay una cosa que es digna de hacerle un estudio, me refiero a la función usb_task() que
está dentro de usb_init(), si hacen la prueba y se ponen hacer la simulación con el
MPLAB descubrirán 2 diferencias habilitando/deshabilitando el conection sense pin,
otra cosa importante hablando del ejemplo anterior sabemos que el código se encierra
dentro de un while
1 ...
2 while(!usb_cdc_connected()){
3 ...
4}
pero y ¿porque el HOST puede seguir reconociendo a la función aún dentro de ese
bucle? si miran dentro de usb_task verán este código:
...
1
enable_interrupts(INT_USB);
2
enable_interrupts(GLOBAL);
3
UIE=__USB_UIF_IDLE | __USB_UIF_RESET; //enable IDLE and RESET
4
USB interrupt
5
usb_state=USB_STATE_POWERED;
esto de alguna manera reconecta a la función para que sea reconocida por el HOST. está
interesante esta parte, vamos a ver adonde llegamos.
1 usb_task():
2 If you use connection sense, and the usb_init_cs() for
3 initialization, then you must periodically call this function to keep
4 an eye on the connection sense pin.
www.unpocodelectronica.netau.net Página 63
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010
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 líneas 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
interrupción
1 void usb_cdc_init(void) {
2 usb_cdc_line_coding.dwDTERrate=9600;
3 usb_cdc_line_coding.bCharFormat=0;
4 usb_cdc_line_coding.bParityType=0;
5 usb_cdc_line_coding.bDataBits=8;
6 (int8)usb_cdc_carrier=0;
7 usb_cdc_got_set_line_coding=FALSE;
8 usb_cdc_break=0;
9 usb_cdc_put_buffer_nextin=0;
10 usb_cdc_get_buffer_status.got=0;
11 usb_cdc_put_buffer_free=TRUE;
12 }
me huele a que en esta llamada se hace una especie de configuración tipo USART.
...
1
if ((usb_state == USB_STATE_ATTACHED)&&(!UCON_SE0)) {
2
UIR=0;
3
UIE=0;
4
enable_interrupts(INT_USB);
5
enable_interrupts(GLOBAL);
6
UIE=__USB_UIF_IDLE | __USB_UIF_RESET; //enable IDLE and RESET USB
7
interrupt
8
usb_state=USB_STATE_POWERED;
9
debug_usb(debug_putc, "\r\n\nUSB TASK: POWERED");
este código ya lo había puesto antes, pues bien, después de un largo rato no pude
simular esa interrupción.
queda una cosa por averiguar: que esa interrupción debe ocurrir cuando hay un
detached, es decir, se desconecta el HOST de la función, ¿porque digo esto?, porque si
sigo simulando me doy cuenta que llego al bucle main y allí caigo en el bucle eterno
www.unpocodelectronica.netau.net Página 64
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010
si nos vamos a la datasheet del 18F4550, Pág. 180 nos encontramos un SFR llamado
UIR
este SFR contiene los flags de los estados de interrupción seleccionados por UIE
www.unpocodelectronica.netau.net Página 65
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010
con este par de bits lo que hacemos es seleccionar el par USB Reset Interrupt y Idle
Detect Interrupt Enable bit
para el RESET:
/********************************************************************
***********
1
/* usb_isr_rst()
2
/*
3
/* Summary: The host (computer) sent us a RESET command. Reset USB
4
device
5
/* and token handler code to initial state.
6
/*
7
/********************************************************************
************/
www.unpocodelectronica.netau.net Página 66
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010
/********************************************************************
***********
1
/* usb_isr_uidle()
2
/*
3
/* Summary: USB peripheral detected IDLE. Put the USB peripheral to
4
sleep.
5
/*
6
/********************************************************************
************/
1
2
3
4
5
6
7
/* ejemplo6_parte4_temp.c
8
en este ejemplo se tratará se ordenará al PIC reconocer la
9
detección del HOST USB de la PC
1
0
adaptación del código original de RRCdcUSB de RedPic
1
Pedro-PalitroqueZ 4/feb/07
1
*/
1
#include <18F4550.h>
2
#fuses
1
XTPLL,NOMCLR,NOWDT,NOPROTECT,NOLVP,NODEBUG,USBDIV,PLL1,CPUDIV1,VREGE
3
N,NOPBADEN
1
#use delay(clock=48000000)
4
1
#define use_portb_lcd TRUE
5
1
#define USB_CON_SENSE_PIN PIN_E3
6
#include <lcd.c>
1
#include "usb_cdc.h"
7
1
void main(){
8
lcd_init(); // llamadas necesarias para iniciar la LCD
1
usb_cdc_init(); // llamadas necesarias para iniciar el módulo USB
9
usb_init(); // llamadas necesarias para iniciar el módulo USB
2
while(!usb_cdc_connected()) { //bucle eterno
0
delay_us(500);
2
}
1
do{
2
usb_task();
2
delay_us(500);
2
}while (TRUE); // bucle eterno
3
}
2
4
2
5
2
6
2
www.unpocodelectronica.netau.net Página 67
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010
7
2
8
1 void usb_attach(void) {
2 usb_token_reset();
3 lcd_putc("\fUSB CONECTADO");
4 delay_ms(100);
5 ...
6 }
7
8 void usb_detach(void) { //done
9 lcd_putc("\fUSB DESCONECTADO");
10 delay_ms(100);
11 ...
12 }
después de revisar bien las conexiones, el .lst para ver si están OK los fuses, se procede
a grabar el PIC y a ensayar:
con el HOST:
sin el HOST:
www.unpocodelectronica.netau.net Página 68
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010
¡arrg! que mala pata, se queda activado el USB CONECTADO aún después de
desconectar al HOST
vamos a repasar, según mi hipótesis para que el módulo USB arranque la función
usb_task() debe esperar por el nivel alto en RE3 (proveniente de Vusb) y si ocurre
selecciona/habilita la interrupción para los casos USB Reset e Idle Detect hasta aquí
vamos bien, ahora ¿que debe ocurrir para que ocurra una de esas 2 interrupciones?
1 #int_usb
2 void usb_isr() {
3 if (usb_state==USB_STATE_DETACHED) return; //should never
4 happen, though
5 if (UIR) {
6 debug_usb(debug_putc,"\r\n\n[%X] ",UIR);
7 if (UIR_ACTV && UIE_ACTV) {usb_isr_activity();} //activity
8 detected. (only enable after sleep)
9
10 if (UCON_SUSPND) return;
11
12 if (UIR_UERR && UIE_UERR) {usb_isr_uerr();} //error
13 has been detected
14
15 if (UIR_URST && UIE_URST) {usb_isr_rst();} //usb reset
16 has been detected
17
18 if (UIR_IDLE && UIE_IDLE) {usb_isr_uidle();} //idle
19 time, we can go to sleep
20 if (UIR_SOF && UIE_SOF) {usb_isr_sof();}
21 if (UIR_STALL && UIE_STALL) {usb_isr_stall();} //a
22 stall handshake was sent
23
www.unpocodelectronica.netau.net Página 69
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010
ahí está otra vez el debug_usb(), me intriga saber como se usa??. esa línea es crucial
porque se puede averiguar quien demonios fue el flag que se activó. voy a ser práctico,
sustituiré a debug_usb por printf así:
y para rematar al poco tiempo me sale un mensaje del windows diciendo que no
reconoce al dispositivo.
54-> 01010100
44-> 01000100
señores, ¡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 solución.
mirando por enésima vez el código 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 código como queramos.
esta usb_init es importante porque habilita o no el módulo USB, ¿y que tal si usamos
esa función en vez de meternos con el driver?
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!
www.unpocodelectronica.netau.net Página 70
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010
1
2
3
4
5
6
7 /* ejemplo6_parte4_temp.c
8 en este ejemplo se tratará se ordenará al PIC reconocer la
9 detección del HOST USB de la PC
1
0 adaptación del código original de RRCdcUSB de RedPic
1 Pedro-PalitroqueZ 4/feb/07
1 */
1 #include <18F4550.h>
2 #fuses
1 XTPLL,NOMCLR,NOWDT,NOPROTECT,NOLVP,NODEBUG,USBDIV,PLL1,CPUDIV1,VREGE
3 N,NOPBADEN
1 #use delay(clock=48000000)
4
1 #define use_portb_lcd TRUE
5
1 #define USB_CON_SENSE_PIN PIN_E3
6 #include <lcd.c>
1 #include "usb_cdc.h"
7
1 void main(){
8 lcd_init(); // llamadas necesarias para iniciar la LCD
1 usb_cdc_init(); // llamadas necesarias para iniciar el módulo USB
9 usb_init(); // llamadas necesarias para iniciar el módulo
2 USB
0 do{
2 usb_task();
1 delay_us(500);
2 }while (TRUE); // bucle eterno
2 }
2
3
2
4
2
5
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
www.unpocodelectronica.netau.net Página 71
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010
ahora si funcionó, aunque fuera por poleo (no veo ninguna interrupción aquí) pero algo
es algo, ya sabemos que: con la función usb_task() podemos determinar el estado de
conexión.
seguro alguien preguntará: ¿bueno pero si no habilito el sense pin hará lo mismo?. y yo
le responderé que no, puesto que con esa deshabilitación, el módulo USB siempre estará
encendido. (comprobado)
www.unpocodelectronica.netau.net Página 72
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010
Quería continuar con un ejemplo práctico (de hecho ya lo comencé), pero hay unos
detalles que vale la pena mencionar.
según el análisis anterior, se dijo que la llamada usb_task() era fundamental, porque a
través de attach() y detach() podíamos hacer las reconexiones, pues bien, esto es muy
cierto, pero hay más, busquemos en la ayuda de CCS varios conceptos:
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
1 powered and can operate without a USB connection.
2
3 usb_task():
4 If you use connection sense, and the usb_init_cs() for
5 initialization, then you must periodically call this function to
6 keep an eye on the connection sense pin.
7
8 When the PIC is connected to the BUS, this function will then
9 perpare the USB peripheral. When the PIC is disconnected from the
10 BUS, it will reset the USB stack and peripheral. Will enable and
11 use the USB interrupt.
12
13 Note: In your application you must define USB_CON_SENSE_PIN to the
14 connection sense pin.
15
16 usb_detach():
17 Removes the PIC from the bus. Will be called automatically by
18 usb_task() if connection is lost, but can be called manually by the
19 user.
20
21 usb_attach():
22 Attaches the PIC to the bus. Will be called automatically by
23 usb_task() if connection is made, but can be called manually by the
24 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.
www.unpocodelectronica.netau.net Página 73
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010
Esta otra llamada usb_init_cs() va de la mano con usb_task(), porque una vez detectada
Vbus a través de USB_CON_SENSE_PIN, en task se procede a conectar el bus.
es cierto porque si quiero hacer transacción de datos con la PC, ambos tienen que estar
de acuerdo.
nota: hay que entender bien porque están 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 /* probando_USB.c
2 es una modificación del ejemplo6_parte4, aquí se usa una bandera
3 global
4 que determinará el estado de conexión del USB, mediante las
5 llamadas
6 usb_attach y usb_detach en pic18_usb.h
7
8 Modificación del código original de RRCdcUSB de RedPic
9 Pedro-PalitroqueZ 11-feb-07
1 */
0 #include <18F4550.h>
1 #fuses
1 XTPLL,NOMCLR,NOWDT,NOPROTECT,NOLVP,NODEBUG,USBDIV,PLL1,CPUDIV1,VREGE
1 N,NOPBADEN
2 #use delay(clock=48000000)
1
3 #define use_portb_lcd TRUE
1 short estado_usb; // boolean global, se debe declarar antes de
4 llamar a usb_cdc.h
1 #define USB_CON_SENSE_PIN PIN_E3
5 #include <lcd.c>
1 #include "usb_cdc.h"
6
1 void mostrar_estado_usb(short bandera);
7
1 void main(){
8 estado_usb=false;
1 usb_cdc_init(); // llamadas necesarias para iniciar el módulo USB
9 usb_init_cs(); // inicia el USB y sale. va a la par con
2 usb_task()
0 lcd_init(); // llamadas necesarias para iniciar la LCD
2 while(true){
1 usb_task(); // configura el USB
2 mostrar_estado_usb(estado_usb);
www.unpocodelectronica.netau.net Página 74
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010
2 if(usb_cdc_connected()){
2 // espera a detectar una transmisión de la PC (Set_Line_Coding)
3 if (usb_enumerated()){ // aquí se hace el acceso HOST<->PC y
2 después sale
4 if(usb_cdc_kbhit()){ //en espera de nuevo(s) caracter(es)
2 en el buffer
5 if(usb_cdc_getc()=='a'){ //¿lo que llegó fué el
2 caracter a?
6
2 printf(usb_cdc_putc, "Llegó la letra a\n\r"); //
7 envia una respuesta al HOST --FALTABA ESTA LÍNEA--
2
8 lcd_gotoxy(1,1);
2 lcd_putc("llego una a ");
9 delay_ms(500);
3 }
0 }
3 }
1 }
3 //*************** aquí se ejecutan otros
2 procesos*********************//
3 lcd_gotoxy(1,1);
3 lcd_putc("otros procesos");
3 delay_ms(500);
4 }
3 }
5 /************************************************
3 // esta llamada imprime en la LCD los estados de conectado
6 // y desconectado del USB dependiendo de la bandera
3 // estado_usb
7 //***********************************************/
3 void mostrar_estado_usb(short bandera){
8 lcd_gotoxy(10,2);
3 if(bandera){
9 lcd_putc(" USB:On");
4 }else{
0 lcd_putc("USB:Off");
4 }
1 delay_ms(500);
4 }
2
4
3
4
4
4
5
4
6
4
7
4
8
4
9
5
0
5
1
5
2
www.unpocodelectronica.netau.net Página 75
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010
5
3
5
4
5
5
5
6
5
7
5
8
5
9
6
0
6
1
6
2
6
3
www.unpocodelectronica.netau.net Página 76
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010
www.unpocodelectronica.netau.net Página 77
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010
97 lblestado.Caption = "Desconectado"
98 End Select
99 Exit Sub
100 End Sub
101
102 ' procedimiento de retardo
103 'este código NO es de mi autoría, lo bajé del internet.
104 Sub Espera(Segundos As Single)
105 Dim ComienzoSeg As Single
106 Dim FinSeg As Single
107 ComienzoSeg = Timer
108 FinSeg = ComienzoSeg + Segundos
109 Do While FinSeg > Timer
110 DoEvents
If ComienzoSeg > Timer Then
FinSeg = FinSeg - 24 * 60 * 60
End If
Loop
End Sub
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 código del PIC, como en VB para que
pudiera observar la ejecución un poco mas lenta, se cumplen todos los casos (en los
ensayos que hice)
casos:
programa en VB:
- de parte del micro, detecta al HOST y lo muestra en pantalla LCD, y ejecuta la
transmisión HOST->PC, aparte que continua ejecutando otros procesos, y todo ello
¡independiente del módulo USB!
¡Ahora si!, vamos con una aplicación. 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 conexión, entonces los datos se mostraran solo en la LCD.
- para ambos casos se indicará en la LCD el estado de conexión.
- se aplicará un mini-protocolo a la transmisión, cuando el software en la PC esté listo
enviará un carácter al PIC y éste deberá recibir dicho carácter para enviar el dato
correspondiente a la PC (una especie de ACK).
www.unpocodelectronica.netau.net Página 78
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010
pero vamos por partes, primero hay que construir el código del CAD y la LCD, es decir,
sin involucrar al USB. Para ello emplearemos al proteus (esto es para agilizar el proceso
de depuración y simulación) y usaremos un pic similar al 18F4550, me refiero al
18F4525.
www.unpocodelectronica.netau.net Página 79
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010
http://www.youtube.com/watch?v=f4igDMssuJ8
otro video:
http://www.youtube.com/watch?v=5Bbe_kR7sFA
notas:
la directiva #DEVICE ADC=16 realiza la justificación a la izquierda, no la usaré en este
ejemplo, porque solamente se puede usar una vez (el compilador te lo dirá).
www.unpocodelectronica.netau.net Página 80
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010
www.unpocodelectronica.netau.net Página 81
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010
62 if(usb_cdc_connected()){
63 // espera a detectar una transmisión de la PC (Set_Line_Coding)
64 if (usb_enumerated()){ // aquí se hace el acceso HOST<->PC y
65 después sale
66 if(usb_cdc_kbhit()){ //en espera de nuevo(s) caracter(es)
67 en el buffer
68 if(usb_cdc_getc()=='a'){ //¿lo que llegó fué el
69 caracter a?
70 printf(usb_cdc_putc,"%Lx", value); // envia el
71 ADRESH:ADRESL al HOST
72 }
73 }
74 }
75 }
76 }
77 }
78 /************************************************
79 // esta llamada imprime en la LCD los estados de conectado
80 // y desconectado del USB dependiendo de la bandera
81 // estado_usb
82 //***********************************************/
83 void mostrar_estado_usb(short bandera){
84 lcd_gotoxy(10,2);
85 if(bandera){
86 lcd_putc(" USB:On");
87 }else{
88 lcd_putc("USB:Off");
89 }
90 //delay_ms(500);
91 }
92 //------------------------------------------------------------------
93 -----------------------
94 // cumple la función de configurar el bit ADFM para hacer
95 // la justificación, también se incluye el retardo por hardware de
96 Tacq
97 // datos de entrada: bandera de justificación
98 // datos de salida: nada
99 //------------------------------------------------------------------
10 -----------------------
0 void config_adcon2(short justificacion){
10 setup_adc(ADC_CLOCK_DIV_64 ); // reloj de conversión = Fosc / 64
1 if(justificacion){
10 #asm
2 bsf 0xFC0,7 // ADFM <- 1
10 #endasm
3 }
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);
}
www.unpocodelectronica.netau.net Página 82
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010
hay otro detalle que nunca he mencionado, ¿a que velocidad transmite esto? cuando se
ejecuta la función usb_cdc_init() aparece:
1 usb_cdc_line_coding.dwDTERrate=9600;
2 usb_cdc_line_coding.bCharFormat=0;
3 usb_cdc_line_coding.bParityType=0;
4 usb_cdc_line_coding.bDataBits=8;
esto forma parte de una estructura en la que sería 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:
www.unpocodelectronica.netau.net Página 83
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010
www.unpocodelectronica.netau.net Página 84
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010
www.unpocodelectronica.netau.net Página 85
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010
www.unpocodelectronica.netau.net Página 86
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010
www.unpocodelectronica.netau.net Página 87
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010
http://www.youtube.com/watch?v=2bs91BHRnBg
http://www.youtube.com/watch?v=rW97fDZA0l0
observaciones y conclusiones:
- Este ejemplo demostró una transmisión HOST<->PIC permitiendo al PIC hacer una
actividad aparte.
este flag debe ser declarado antes de usb_cdc.h porque hay una función allí que hace
uso de ella y sirve para mostrar los estados de: USB -> conectado/desconectado.
Específicamente dentro de usb_attach() y usb_detach().
- en el último ejemplo, usé 2 videos en vez de uno. porque el camtasia studio interfería
de manera extraña en la transmisión de datos cuando iniciaba una grabación (el
programa en VB se colgaba durante la grabación)
www.unpocodelectronica.netau.net Página 88
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010
Conociendo al SnoopyPRO
1
SnoopyPro is a tool for advanced USB programmers. It allows you to
2
record each URB sent to and received from a USB device. This traces
3
can be saved, loaded, edited, printed and combined into new traces.
4
5
WARNING: You might damage your system with this tool. Don't use it
6
if you don't know what you're doing!!!! We're not responsible for
7
anything that happens to you, your system, your devices, your
8
marriage, etc. etc.
9
...
1
0
====================================================================
1
======
1
INSTALLATION/USE:
1
====================================================================
2
======
1
3
1. Run SnoopyPro.exe from whereever you have saved it.
1
2. Open up the USB devices window with F2.
4
3. Choose 'Unpack Drivers' from the 'File' menu.
1
4. Choose 'Install Service' from the 'File' menu.
5
5. Locate the device you want to sniff.
1
6. Right-click on it and choose 'Install and Restart'.
6
7. Wait for the magic to happen...
1
...
7
www.unpocodelectronica.netau.net Página 89
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010
Iniciando el SnoopyPro
cargamos la aplicación en VB
www.unpocodelectronica.netau.net Página 90
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010
Probando el SnoopyPro
empezamos a husmear. Después de unas decenas de líneas nos encontramos con esta:
www.unpocodelectronica.netau.net Página 91
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010
coincide con el carácter “a” que se envía al PIC en hexa ¿coincidencia?. si miramos
unas líneas mas abajo, no encontramos con un par de caracteres mas y una cadena:
Llegó la letra a
4C 6C 65 67 F3 20 6C 61 20 6C 65 74 72 61 20 61
¡muy interesante!
www.unpocodelectronica.netau.net Página 92
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010
las posibles respuestas a estas, sin ánimo de desilusionar a nadie (incluyéndome) vean
esto (mitos y realidades página 9 de 858_USB.pdf):
una cosa que hay que tener en consideración y sobre todo para lo que estudiamos esto
en lenguaje de alto nivel, el protocolo de transmisión USB también lo llaman la pila
USB
www.unpocodelectronica.netau.net Página 93
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010
observen que tiene cierto parecido al modelo OSI. en las capas superiores tenemos las
funciones básicas que el usuario puede realizar (comunicación lógica). esto a su vez va
a parar a la segunda capa y luego a la tercera capa(comunicación física) que involucra el
aspecto eléctrico. En nuestro caso estaríamos directamente metidos en la capa superior,
pero algunas veces entrando en las otras dos:
esta tema es fascinante pero a la vez extenso, así que hay que ir por partes para no
perdernos.
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
www.unpocodelectronica.netau.net Página 94
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010
tratando de meter un poco de teoría a cada línea que nos encontremos y siguiendo el
mismo método anterior: analizando el código a la inversa.
1 //// PicUSB.c
2 ////
3 ////
4 ////
5 //// Este ejemplo muestra como desarrollar un sencillo dispositivo
6 ////
7 //// USB con el PIC18F2550, aunque puede ser facilmente adaptado
8 ////
9 //// para la serie 18Fxx5x. Se suministra el PicUSB.exe, así como
10 ////
11 //// su código fuente para Visual C# 2005, podréis encontrar tb
12 ////
13 //// los drivers para el dispositivo. No se suministra esquema de
14 ////
15 //// conexión puesto que está pensado para ser usado en el GTP USB,
16 ////
17 //// cualquiera de las tres versiones disponibles, si aun no teneis
18 ////
19 //// el programador, podeis utilizar el esquema de ese proyecto.
20 ////
21 ////
22 ////
23 //// Cuando el dispositivo sea conectado al PC, saldrá el asistente
24 ////
25 //// para la instalación del driver. Instala el suministrado junto
26 ////
27 //// a este ejemplo, lo encontrareis dentro de la carpeta Driver.
28 ////
29 //// Una vez instalado podreis usar el PicUSB.exe para encender o
30 ////
31 //// apagar el led bicolor del GTP USB, y para realizar la suma de
32 ////
33 //// dos números introducidos.
34 ////
35 ////
36 ////
37 //// Realizado con el compilador CCS PCWH 3.227
38 ////
39 ////
40 ////
41 //// Por: Jaime Fernández-Caro Belmonte hobbypic@hotmail.com
42 ////
43 ////
44 ////
45 //// http://www.hobbypic.com
46 ////
47 ///////////////////////////////////////////////////////////////////
48 //////
49 #include <18F4550.h>
50 //#fuses
51 HSPLL,NOWDT,NOPROTECT,NOLVP,NODEBUG,USBDIV,PLL3,CPUDIV1,VREGEN
52 #fuses
53 XTPLL,MCLR,NOWDT,NOPROTECT,NOLVP,NODEBUG,USBDIV,PLL1,CPUDIV1,VREGEN
54 ,NOPBADEN // el fuse
55 // modificado para USB -> VREGEN
www.unpocodelectronica.netau.net Página 95
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010
56 #use delay(clock=48000000)
57
58 ///////////////////////////////////////////////////////////////////
59 //////////
60 //
61 // CCS Library dynamic defines. For dynamic configuration of the
62 CCS Library
63 // for your application several defines need to be made. See the
64 comments
65 // at usb.h for more information
66 //
67 ///////////////////////////////////////////////////////////////////
68 //////////
69 #define USB_HID_DEVICE FALSE //deshabilitamos el
70 uso de las directivas HID
71 #define USB_EP1_TX_ENABLE USB_ENABLE_BULK //turn on
72 EP1(EndPoint1) for IN bulk/interrupt transfers
73 #define USB_EP1_RX_ENABLE USB_ENABLE_BULK //turn on
74 EP1(EndPoint1) for OUT bulk/interrupt transfers
75 #define USB_EP1_TX_SIZE 1 //size to allocate for
76 the tx endpoint 1 buffer
77 #define USB_EP1_RX_SIZE 3 //size to allocate for
78 the rx endpoint 1 buffer
79
80
81 ///////////////////////////////////////////////////////////////////
82 //////////
83 //
84 // If you are using a USB connection sense pin, define it here. If
85 you are
86 // not using connection sense, comment out this line. Without
87 connection
88 // sense you will not know if the device gets disconnected.
89 // (connection sense should look like this:
90 // 100k
91 // VBUS-----+----/\/\/\/\/\----- (I/O PIN ON PIC)
92 // |
93 // +----/\/\/\/\/\-----GND
94 // 100k
95 // (where VBUS is pin1 of the USB connector)
96 //
97 ///////////////////////////////////////////////////////////////////
98 //////////
99 //#define USB_CON_SENSE_PIN PIN_B2 //CCS 18F4550 development kit
10 has optional conection sense pin
0
10 ///////////////////////////////////////////////////////////////////
1 //////////
10 //
2 // Include the CCS USB Libraries. See the comments at the top of
10 these
3 // files for more information
10 //
4 ///////////////////////////////////////////////////////////////////
10 //////////
5 #include <pic18_usb.h> //Microchip PIC18Fxx5x Hardware layer
10 for CCS's PIC USB driver
6 #include <PicUSB.h> //Configuración del USB y los
10 descriptores para este dispositivo
7 #include <usb.c> //handles usb setup tokens and get
10 descriptor reports
www.unpocodelectronica.netau.net Página 96
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010
8
10
9 ///////////////////////////////////////////////////////////////////
11 //////////
0 //
11 // Al conectar el PicUSB al PC encendemos el Led Rojo hasta que el
1 dispositivo
11 // halla sido configurado por el PC, en ese momento encederemos el
2 Led Verde.
11 // Esperaremos hasta que se reciba un paquete proveniente del PC.
3 Comprobaremos
11 // el primer byte del paquete recibido para comprobar si queremos
4 entrar en el
11 // modo Suma, donde se realizará una suma de dos operandos, que
5 corresponderan
11 // con los dos bytes restantes del paquete recibido; una vez
6 realizada la suma
11 // enviaremos el paquete con el resultado de vuelta al PC. Si
7 entramos en el
11 // modo Led comprobaremos el segundo byte del paquete recibido para
8 comprobar
11 // si deberemos apagar los leds, encender el verder o el rojo.
9 //
12 ///////////////////////////////////////////////////////////////////
0 //////////
12 #define LEDV PIN_B6
1 #define LEDR PIN_B7
12 #define LED_ON output_high
2 #define LED_OFF output_low
12
3 #define modo recibe[0]
12 #define param1 recibe[1]
4 #define param2 recibe[2]
12 #define resultado envia[0]
5
12
6 void main(void) {
12
7 int8 recibe[3]; //declaramos variables
12 int8 envia[1];
8
12 LED_OFF(LEDV); //encendemos led rojo
9 LED_ON(LEDR);
13
0 usb_init(); //inicializamos el USB
13
1 usb_task(); //habilita periferico usb e
13 interrupciones
2 usb_wait_for_enumeration(); //esperamos hasta que el PicUSB
13 sea configurado por el host
3
13 LED_OFF(LEDR);
4 LED_ON(LEDV); //encendemos led verde
13
5 while (TRUE)
13 {
6 if(usb_enumerated()) //si el PicUSB está configurado
{
if (usb_kbhit(1)) //si el endpoint de salida
contiene datos del host
{
www.unpocodelectronica.netau.net Página 97
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010
if (modo == 0) // Modo_Suma
{
resultado = param1 + param2; //hacemos la suma
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í están 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
y resulta que en los driver´s del CCS viene activado por defecto.
voy a colocar aquí una explicación que me pareció excelente tomada de un proyecto
especial de grado link Capitulo 3: Bus Serie Universal, funcionamiento Pág. 38
www.unpocodelectronica.netau.net Página 98
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010
cita:
...
"Los dispositivos (o mejor dicho, las funcionas) tienen asociados
unos canales
lógicos unidireccionales (llamados pipes) que conectan al host
1 controlador con
2 una entidad lógica en el dispositivo llamada endpoint. Los datos son
3 enviados
4 en paquetes de largo variable (potencia de 2). Típicamente estos
5 paquetes son
6 de 64, 128 o más bytes.
7 Estos endpoints (y sus respectivos pipes) son numerados del 0 al 15
8 en cada
9 dirección, por lo cual un dispositivo puede tener hasta 32 endpoints
10 (16 de
11 entrada y 16 de salida). La dirección se considera siempre desde el
12 punto de
13 vista del host controlador. Así un endpoint de salida será un canal
14 que
15 transmite datos desde el host controlador al dispositivo. Un
endpoint solo
puede tener una única dirección. 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 módulo USB existen 16 de salida (OUT) y 16 de entrada (IN) pero
agrupados en forma bidirecional, de acuerdo a un par de bits de configuración (ver Pág.
171). Ojo un endpoint es unidireccional.
www.unpocodelectronica.netau.net Página 99
[PRIMEROS PASOS CON EL 18F4550] 14 de abril de 2010
· transferencias de control:
usado para comandos (y respuestas) cortos y simples. Es el tipo de transferencia usada
por el pipe 0
· transferencias isócronas:
proveen un ancho de banda asegurado pero con posibles pérdidas de datos. Usado
típicamente para audio y video en tiempo real
· transferencias interruptivas:
para dispositivos que necesitan una respuesta rápida (poca latencia), por ejemplo, mouse
y otros dispositivos de interacción humana.
podemos definir el tamaño del buffer en bytes, el límite lo tendremos que buscar en el
driver correspondiente (con FS hasta 64 bytes por transacción).
nota: no confundir FS con HS, con High Speed se llega hasta 480Mbps, el módulo USB
del pic soporta Full Speed = 12Mbps
para propósitos donde queramos hacer otras actividades en el PIC, usaremos el segundo.
ahora hablaremos de como se hace para transmitir y recibir datos. para eso están
usb_put_packet(,,) y usb_get_packet(,,) ambas necesitan de 3 argumentos. vamos con
put_packet:
1 ...
2 /* usb_put_packet(endpoint,*ptr,len,toggle)
3 /*
4 /* Input: endpoint - endpoint to send packet to
5 /* ptr - points to data to send
6 /* len - amount of data to send
7 /* toggle - whether to send data with a DATA0 pid, a DATA1
8 pid, or toggle from the last DATAx pid.
9 /*
10 /* Output: TRUE if data was sent correctly, FALSE if it was not.
11 The only reason it will
12 /* return FALSE is if because the TX buffer is still full
como parte de su protocolo, nos encontraremos entre otras cosas que USB maneja la
transmisión de datos por paquetes, llamados TOKEN en la cuál el HOST es el iniciador
de todas las transferencias que se producen en el BUS [2]
pues bien en la parte de transmisión 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 sincronización del data toggle. a grandes rasgos esto
no es mas que un método de validación 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 sincronización transmisor <-> receptor.
Transacciones Consecutivas
según la página 174 de 39632c.pdf el data toggle está definido por un bit llamado
DTSEN y es mas, allí lo explican.
hay toda una teoría en lo relacionado a los grupos de paquetes, no lo mencionaré para
no salirme del objetivo principal.
usb_get_packet()
1
2 /*******************************************************************
3 ************
4 /* usb_get_packet(endpoint, *ptr, max)
5 /*
6 /* Input: endpoint - endpoint to get data from
7 /* ptr - where to save data to local PIC RAM
8 /* max - max amount of data to receive from buffer
9 /*
1 /* Output: the amount of data taken from the buffer.
0 /*
1 /* NOTE - IF THERE IS NO PACKET TO GET YOU WILL GET INVALID
1 RESULTS!
1 /* VERIFY WITH USB_KBHIT() BEFORE YOU CALL
2 USB_GET_PACKET()!
1 /*
3 /* Summary: Gets a packet of data from the USB buffer and puts into
1 local PIC RAM.
4 /* Until you call usb_get_packet() the data will sit in the
1 endpoint
5 /* buffer and the PC will get NAKs when it tries to write
1 more data
6 /* to the endpoint.
1 ...
7
-vaya- se fue todo en pura teoría, entonces en la próxima parte veremos si hacemos el
estudio del lado del HOST mediante mpusbapi.dll y como hacerla funcionar por ej: en
VB a través de una Interfaz de Programación de Aplicaciones ó API
http://pablohoffman.com/oscusb/doc/
http://pablohoffman.com/oscusb/
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 también añade
otras posibilidades (PWM, CAD)
lo primero, probar el código. ¡Claro! jeje y grabar el firmware PICusb en el PIC. Esto ya
lo hice varios post atrás, pero no lo expliqué y ahora le toca el turno al Visual Basic
usando el programa1.
como mencioné anteriormente, para usar nuestra aplicación corriendo en VB, tenemos
que hacer uso de unas llamadas a la librería mpusbapi.dll (apis).
aquí aparecen 7 ,yo conté unas 10 en el código fuente. parece que estas 7 son las
necesarias para hacer transacciones a la función.
MPUSBGetDLLVersion(Void)
1 Lee el nivel de revision del MPUSAPi.dll. Es un nivel de revision de
2 32bits. Esta funcion no devuelve la version del codigo, no realiza
nada con el USB.
nos arroja 10000, y pienso que como hay 8 dígitos, ya que la versión es en hexa (8
nibbles = 32bits) -> versión dll = 1.0.0.0.0
veamos:
¿quién es openMPUSBDevice?
Sub OpenMPUSBDevice()
1 myOutPipe = MPUSBOpen(0, vid_pid, out_pipe, 0, 0) 'como
2 salida
3 myInPipe = MPUSBOpen(0, vid_pid, in_pipe, 1, 0) 'como
4 entrada
End Sub
si para ambos tenemos como resultado -1 -> entonces quiere decir que no se pudo
establecer el enlace lógico con el dispositivo.
INVALID_HANDLE_VALUE = -1
para terminar la aplicación, debemos cerrar el enlace (igual como se hace en RS-232)
mediante:
1 Sub CloseMPUSBDevice()
2 MPUSBClose (myOutPipe)
3 MPUSBClose (myInPipe)
4 End Sub
nota: es bueno añadirle el método debug.print a cada api para poder analizar cada línea
ejecutada:
Sub OpenMPUSBDevice()
1 myOutPipe = MPUSBOpen(0, vid_pid, out_pipe, 0, 0) 'como
2 salida
3 Debug.Print "myOutPipe= " & myOutPipe
4
5 myInPipe = MPUSBOpen(0, vid_pid, in_pipe, 1, 0) 'como
6 entrada
7 Debug.Print "myInPipe= " & myInPipe
End Sub
vamos a escribir un código para abrir y cerrar un enlace virtual con el dispositivo. ¿les
parece?
1 Option Explicit
2
3 Private Declare Function MPUSBOpen Lib "mpusbapi.dll" (ByVal
4 instance As Long, ByVal pVID_PID As String, ByVal pEP As String,
5 ByVal dwDir As Long, ByVal dwReserved As Long) As Long
6 Private Declare Function MPUSBClose Lib "mpusbapi.dll" (ByVal handle
7 As Long) As Long
8
9 Const INVALID_HANDLE_VALUE = -1
10 Const MPUS_FAIL = 0
11 Const MPUSB_SUCCESS = 1
12
13
14 Const vid_pid = "vid_04d8&pid_0011" ' Vendor id (Microchip) y
15 Periferico id
16 Const out_pipe = "\MCHP_EP1" ' endpoint 1
17 Const in_pipe = "\MCHP_EP1" ' endpoint 1
18
19 Const MP_WRITE = 0 '
20 Const MP_READ = 1
21
22 Public myInPipe As Long ' para guardar el manejador
23 Public myOutPipe As Long
24
25
26 Private Sub cmdabrir_Click() ' abrir enlace o pipe
27 myOutPipe = MPUSBOpen(0, vid_pid, out_pipe, 0, 0)
28 'como salida
29 Debug.Print "myOutPipe= " & myOutPipe ' para monitoreo
30
31 If myOutPipe = INVALID_HANDLE_VALUE Then ' si es -1
32 lblpipeout = "Fallo el enlace de salida"
33 Else
34 lblpipeout = "Enlace salida establecido"
35 End If
36
37 myInPipe = MPUSBOpen(0, vid_pid, in_pipe, 1, 0)
38 'como entrada
39 Debug.Print "myInPipe= " & myInPipe
40
41 If myInPipe = INVALID_HANDLE_VALUE Then
42 lblpipein = "Fallo el enlace de entrada"
43 Else
44 lblpipein = "Enlace entrada establecido"
45 End If
46
47 End Sub
48
49 Private Sub cmdcerrar_Click() ' cerrar enlace pipe
50 Dim resul_o As Long: Dim resul_i As Long
51 resul_o = MPUSBClose(myOutPipe)
52 Debug.Print "MPUSBClose(myOutPipe)= " & resul_o
53 If resul_o = MPUSB_SUCCESS Then
54 lblpipeout.Caption = "Enlace salida cerrado"
55 Else
56 lblpipeout.Caption = "Error al cerrar el enlace salida,
57 puede que este cerrado"
58 End If
59 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
MPUSBRead
MPUSBWrite
es lógico 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 había visto, además no pertenece al
VB en sí, leyendo por aquí, por acá, conseguí:
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 dirección donde está alojado el dato que queremos enviar
el problema que tiene visual basic es que no podemos usar punteros, pero con el método
varptr podemos tomar dicha dirección, y esto no es lo mejor de todo, léase 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 dirección 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 código donde:
Unload Me
End Sub
así pues, donde veamos el varptr ya sabemos a que se está refiriendo, además el
argumento de la api también lo delata con la letra „p‟ ej: pData, pLenght
como verán esta es otra aplicación del concepto del puntero, por un lado tenemos la
casilla(dirección de almacenamiento) y por el otro tenemos el valor del dato
almacenado.
el resto de los argumentos es fácil de entender, como la longitud del dato (en bytes).
esto depende de como configuremos el envío desde el dispositivo
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)
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 acción para ambos led´s (apagado, on, off -> led rojo y verde)
aquí sucede lo contrario, es decir, la api MPUSBRead necesita la dirección del byte ‟s‟
para almacenar el dato que viene del PIC (que en este caso es 1 byte de longitud).
vamos a usar el estupendo SnoopyPro para ver los búferes del USB jijiji
Transacción Recibida
Transacción Recibida
Transacción Recibida
Transacción Recibida
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.
analizando paquetes
analizando paquetes
observaciones:
- después de haber visto varias veces el código de Jaime hasta ahora es que me doy
cuenta que el led verde es RB6 y led rojo RB7 yo lo tenía invertido. pero lo extraño de
todo es que con el programa PicUSBDelphi.exe de Diego se ejecuta OK con los led´s
invertido. ¿¿??
- 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 también 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
quisiera hacer unas observaciones, varios mensaje atrás hablando sobre la api
MPUSBGetDLLVersion() escribí:
cita:
nos arroja 10000, y pienso que como hay 8 dígitos, ya que la versión
1
es en hexa (8 nibbles = 32bits) -> versión dll = 1.0.0.0.0
bueno, ahora no estoy tan seguro que eso sea cierto (después de todo es una suposición),
ahora me baso en lo siguiente:
- que dicha api, devuelve un puntero que contiene la versión de la librería mpusbapi.dll
aquí está un adjunto con un programa en visual basic que hace lo que digo.
está planteado así al momento de escribir esto, pudiéndose cambiar por la versión
correcta posteriormente (dado el caso).
voy a tomar el ejemplo del CDC explicado con anterioridad y lo voy a modificar para
usarlo con la librería mpusbapi.dll
1 /* ejemplo7_parte4.c
2 se pretende hacer la deteccion de conexion al puerto USB, mediante
3 la mpusbapi.dll
4 mostrando en una pantalla LCD 2x16 el estado.
5
6 Este codigo es un hibrido del cual se tomo partes de:
7 - PicUSB.c de J1M
8 - RRCdcUSB de RedPic
9 - probando_USB.c del ejemplo6_parte5 de PalitroqueZ
1
0 Pedro - PalitroqueZ 07-Mar-2007. Hora: 3:54 PM
1 */
1
1 #include <18F4550.h>
2 #fuses
1 XTPLL,NOMCLR,NOWDT,NOPROTECT,NOLVP,NODEBUG,USBDIV,PLL1,CPUDIV1,VREGE
3 N,NOPBADEN
1 #use delay(clock=48000000)
4
1 #define use_portb_lcd TRUE
5
1 #define USB_HID_DEVICE FALSE //deshabilitamos el uso
6 de las directivas HID
1 #define USB_EP1_TX_ENABLE USB_ENABLE_BULK //turn on
7 EP1(EndPoint1) for IN bulk/interrupt transfers
1 #define USB_EP1_RX_ENABLE USB_ENABLE_BULK //turn on
8 EP1(EndPoint1) for OUT bulk/interrupt transfers
1 #define USB_EP1_TX_SIZE 1 //size to allocate for
9 the tx endpoint 1 buffer
2 #define USB_EP1_RX_SIZE 1 //size to allocate for
0 the rx endpoint 1 buffer
2
1 #define USB_CON_SENSE_PIN PIN_E3
2
2 #include <pic18_usb.h> //Microchip PIC18Fxx5x Hardware layer for
2 CCS's PIC USB driver
3 #include "PicUSB.h" //Configuración del USB y los descriptores
2 para este dispositivo
4 #include <usb.c> //handles usb setup tokens and get
2 descriptor reports
5 #include <lcd.c>
2
6 void mostrar_estado_usb();
2
7 void main(){
2 int envia[1];
8 int recibe[1];
2 envia[0]='a';
9 usb_init_cs(); // inicializa el USB y lo desactiva
3 lcd_init(); // llamadas necesarias para iniciar la LCD
0 while(true){
3 usb_task(); //habilita periferico usb e interrupciones
1 mostrar_estado_usb();
3 if(usb_enumerated()){ // primer if
2 if(usb_kbhit(1)){ // segundo if
3 //si el endpoint de salida contiene datos del host
3 usb_get_packet(1, recibe, 1);
3 //cojemos el paquete de tamaño 1bytes del EP1 y
4 almacenamos en recibe
3 if(recibe[0]=='a'){ // tercer if
5 usb_put_packet(1, envia, 1, USB_DTS_TOGGLE);
3 //enviamos el paquete de tamaño 1byte del EP1 al PC
6 lcd_gotoxy(1,1);
3 lcd_putc("llego una a ");
7 delay_ms(500);
3 } // fin del tercer if
8 } // fin del segundo if
3 } // fin del primer if
9 lcd_gotoxy(1,1);
4 lcd_putc("otros procesos");
0 delay_ms(500);
4 } // fin del ciclo while
1 }
4 /************************************************
2 // esta llamada imprime en la LCD los estados de conectado
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.
la función:
1 void usb_init(void) {
2 usb_init_cs();
3
4 do {
5 usb_task();
6 } while (usb_state != USB_STATE_POWERED);
7}
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 módulo USB y lo desactiva, está bien así que se desactive
por defecto (menos consumo para el circuito).
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á.
- el resto del código queda igual, solo ajustar los paquetes de datos a 1 byte, usando un
eco. el HOST le envía un carácter (a) y el dispositivo se lo devuelve.
volver arriba
52 Timer1.Enabled = True
53 End Sub
54
55 Private Sub Form_Unload(Cancel As Integer)
56 CloseMPUSBDevice 'cierra comunicaciones
57 End Sub
58
59 Private Sub Timer1_Timer()
60 OpenMPUSBDevice 'abre comunicaciones
61 If (myOutPipe <> INVALID_HANDLE_VALUE) And (myInPipe <>
62 INVALID_HANDLE_VALUE) Then
63 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 empeño 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 código del PIC es el mismo del ejemplo anterior y funciona igual.
los paquetes de datos se mantienen en 1 byte, hice pruebas con 64 bytes, y los
resultados fueron casi los mismos.
1 /* ejemplo8_parte1.c
2 adaptación del ejemplo6parte6. transmision del resultado del CAD
3 al PC
4 al puerto USB, mediante la mpusbapi.dll
5 mostrando en una pantalla LCD 2x16 el resultado del CAD y el
6 estado USB.
7
8 Este código es un híbrido del cuál se tomó partes de:
9 - PicUSB.c de J1M
10 - RRCdcUSB de RedPic
11 - probando_USB.c del ejemplo6_parte5 de PalitroqueZ
12
13 Pedro - PalitroqueZ 08-Mar-2007. Hora: 9:01 AM
14 */
15
16 #include <18F4550.h>
17 #DEVICE ADC=8 // cad a 8 bits
18 #fuses
19 XTPLL,NOMCLR,NOWDT,NOPROTECT,NOLVP,NODEBUG,USBDIV,PLL1,CPUDIV1,VREGE
20 N,NOPBADEN
21 #use delay(clock=48000000)
22
23 #define use_portb_lcd TRUE
24
25 #define USB_HID_DEVICE FALSE //deshabilitamos el uso
26 de las directivas HID
27 #define USB_EP1_TX_ENABLE USB_ENABLE_BULK //turn on
28 EP1(EndPoint1) for IN bulk/interrupt transfers
29 #define USB_EP1_RX_ENABLE USB_ENABLE_BULK //turn on
30 EP1(EndPoint1) for OUT bulk/interrupt transfers
31 #define USB_EP1_TX_SIZE 1 //size to allocate for
32 the tx endpoint 1 buffer
33 #define USB_EP1_RX_SIZE 1 //size to allocate for
34 the rx endpoint 1 buffer
35
36 #define USB_CON_SENSE_PIN PIN_E3
37 #define DERECHA 0
38
39 #include <pic18_usb.h> //Microchip PIC18Fxx5x Hardware layer for
40 CCS's PIC USB driver
41 #include "PicUSB.h" //Configuración del USB y los descriptores
42 para este dispositivo
43 #include <usb.c> //handles usb setup tokens and get
44 descriptor reports
45 #include <lcd.c>
46
47 void mostrar_estado_usb();
48 void config_adcon2(short justificacion);
49
50 int value;
51
52 void main(){
53 int i;
54 int envia[1];
55 int recibe[1];
56
57 set_tris_a(0x1); // Ra[0]=entradas, los demas=salida
58
59 usb_init_cs(); // inicializa el USB y lo desactiva
60 lcd_init(); // llamadas necesarias para iniciar la LCD
61 setup_adc_ports( AN0 || VSS_VDD ); // canal AN0, Vref+ = Vdd,
62 Vref- = Vss
63 config_adcon2(DERECHA); // justificación derecha, Tacq= 2Tad
64
65 while(true){
66 usb_task(); //habilita periferico usb e interrupciones
67 mostrar_estado_usb();
68 envia[0]= read_adc();
69
70 for(i=0;i<16;i++){// muestra resultado del CAD en binario,
71 linea1 LCD
72 lcd_gotoxy(16-i,1);
73 lcd_putc((char)(bit_test(envia[0],i)+0x30));
74 }
75 printf(lcd_putc,"\n0x%Lx",envia[0]);
76 // muestra el resultado del CAD en Hexa, linea2 LCD
77
78 if(usb_enumerated()){ // primer if
79 if(usb_kbhit(1)){ // segundo if
80 //si el endpoint de salida contiene datos del host
81 usb_get_packet(1, recibe, 1);
82 //cojemos el paquete de tamaño 1bytes del EP1 y
83 almacenamos en recibe
84 if(recibe[0]=='a'){ // tercer if
85 usb_put_packet(1, envia, 1, USB_DTS_TOGGLE);
86 //enviamos el paquete de tamaño 1 bytes del EP1 al
87 PC
88 } // fin del tercer if
89 } // fin del segundo if
90 } // fin del primer if
91 } // fin del ciclo while
92 }
93 /***********************************************************
94 // esta llamada imprime en la LCD los estados de conectado
95 // y desconectado del USB dependiendo de la bandera
96 // estado_usb
97 //**********************************************************/
98 void mostrar_estado_usb(){
99 lcd_gotoxy(10,2);
10 if(usb_attached()){
0 lcd_putc(" USB:On");
10 }else{
1 lcd_putc("USB:Off");
10 }
2 // delay_ms(500);
10 }
3 //------------------------------------------------------------------
10 -----------------------
4 // cumple la función de configurar el bit ADFM para hacer
10 // la justificación, también se incluye el retardo por hardware de
5 Tacq
10 // datos de entrada: bandera de justificación
6 // datos de salida: nada
10 //------------------------------------------------------------------
7 -----------------------
10 void config_adcon2(short justificacion){
8 setup_adc(ADC_CLOCK_DIV_64 ); // reloj de conversión = Fosc / 64
10 if(justificacion){
9 #asm
11 bsf 0xFC0,7 // ADFM <- 1
0 #endasm
11 }
1 else{
11 #asm
2 bcf 0xFC0,7 // ADFM <- 0
11 #endasm
3 }
11 #asm // configura Tacq = 2Tad
4 bsf 0xFC0,3
11 bcf 0xFC0,4
5 bcf 0xFC0,5
#endasm
set_adc_channel(0);
}
int envía[1];
int recibe[1];
16
17 Option Explicit
18
19 Dim cx As Integer, cy As Integer
20 Dim cx1 As Integer, cy1 As Integer
21 Dim i As Integer, j As Long
22 Dim x As Long, y As Integer
23 Dim dato(1000) As Long
24 Dim pcx As Long, pcy As Long
25 Dim fcx As Long, fcy As Long
26 Dim n As Integer ' n define la base de tiempo o time-division
27
28 Dim Send_Buf(0) As Byte
29 Const verde = &HFF00&
30 Const rojo = &HFF&
31
32 Dim valor As Single, maximo As Integer
33 Dim te As Byte
34
35 Private Sub Form_Load()
36 valor = 0 'VScroll1.Value
37 ' el resultado del CAD en un tiempo discreto
38 maximo = 255 'VScroll1.Max
39 ' viene siendo el maximo numero de pasos del CAD (8 bits=255,
40 10 bits=1023)
41 n = 30
42 ' wl time-division
43 cy = Picture1.ScaleHeight ' 117
44 cx = Picture1.ScaleWidth ' 253
45
46 cy1 = Picture1.ScaleHeight ' 117
47 cx1 = Picture1.ScaleWidth ' 253
48
49 pcx = Picture1.Width
50 pcy = Picture1.Height
51
52 fcx = Me.Width
53 fcy = Me.Height
54
55 ajustar_tiempo (n)
56
57 Timer1.Enabled = False
58 Timer2.Enabled = False
59 Timer3.Interval = 50
60 Timer3.Enabled = True
61 'Timer3.Enabled = False
62
63 HScroll1.Value = n
64 End Sub
65
66 Private Sub Form_Resize()
67 Timer1.Enabled = False
68 Timer2.Enabled = False
69
70 Picture1.Height = Form1.Height / (fcy / pcy)
71 Picture1.Width = Form1.Width / (fcx / pcx)
72
73 Picture1.ScaleHeight = Picture1.Height / (pcy / cy1)
74 Picture1.ScaleWidth = Picture1.Width / (pcx / cx1)
75 cy = Picture1.ScaleHeight
76 cx = Picture1.ScaleWidth
77 Picture1.Cls
78 x = -1: y = 0: i = 0: j = -1
79 ajustar_tiempo (n)
80 Timer1.Enabled = True
81
82 End Sub
83
84 Private Sub Form_Unload(Cancel As Integer)
85
86 CloseMPUSBDevice 'cierra comunicaciones
87
88 End Sub
89
90 Private Sub HScroll1_Change()
91 n = HScroll1.Value
92 lblconta.Caption = n
93 Form_Resize
94 End Sub
95
96 Private Sub HScroll1_Scroll()
97 lblconta.Caption = HScroll1.Value
98 End Sub
99
100 Private Sub Timer1_Timer()
101 Label1.Caption = VScroll1.Value
102
103 dato(i + 1) = Int(cy - valor * (cy / maximo))
104 If Not j > (cx - n) Then ' pregunta si i no ha llegado a cx
105 Picture1.Line (x, dato(i))-(j, dato(i + 1)), vbBlack
106 x = j
107 i = i + 1
108 j = j + n
109 Else
110 Timer1.Enabled = False ' ya llego, deja de dibujar
111 Timer2.Enabled = True '
112 End If
113 Label1.Caption = "CAD= " & Round(valor * (5 / maximo), 3) & " volts
114 -> 0x" & Hex(valor)
115 End Sub
116
117 Private Sub Timer2_Timer()
118 Picture1.Cls
119 x = -1
120 j = -1
121
122 Label1.Caption = VScroll1.Value
123 'valor = VScroll1.Value
124 If n > 1 Then
125 dato(Int((cx / n) + 2)) = Int(cy - valor * (cy / maximo))
126 Else
127 dato(Int((cx / n)) + 1) = Int(cy - valor * (cy / maximo))
128
129 End If
130 For i = 0 To cx ' pregunta si i no ha llegado a cx
131 Picture1.Line (x, dato(i))-(j, dato(i + 1)), vbBlack
132 x = j
133 j = j + n ' para lograr el ajuste time-division
134 dato(i) = dato(i + 1) ' rellenar el dato(n) : 0 < n < cx
135 Next i
136 Label1.Caption = "CAD= " & Round(valor * (5 / maximo), 3) & "
137 volts -> 0x" & Hex(valor)
End Sub
un ventanazo en acción:
http://www.youtube.com/watch?v=l9AdEIxAzgo
en base a mis experiencias, debo decir que trabajar con mpusbapi.dll como que es la
mejor opción, mucho mas rápido y práctico (conociendo la programación). pero para no
subestimar a la clase CDC, entonces:
- eso dependerá del programador que tendrá que decidir cuál es mejor.
y este fue el estudio realizado al módulo USB si se quiere decir „por encima‟ ya que
queda mucha información a nivel de capas inferiores por estudiar.
Agradecimientos y Méritos
Foro Todopic
Diego (RedPic) en PicManía
Jaime (J1M) en hobbypic.com
Microchip
Manolo Nocturno con la Wikipic
Sisco por su software WinPic800
Guillermos (Slalen) en Electronics‟ Strange World
www.unpocodelectronica.netau.net