Autor Tema: Protocolo pic16f84 - puerto paralelo  (Leído 5821 veces)

0 Usuarios y 1 Visitante están viendo este tema.

Desconectado smrenderos

  • MiembrosReales
  • *
  • Mensajes: 17
Protocolo pic16f84 - puerto paralelo
« : noviembre 13, 2010, 03:58:59 am »
Estoy realizando un proyecto para controlar 3 servomotores a traves del puerto paralelo en C++, uso el pic16f84a para comunicarme con el puerto y controlar los motores (con retardos genero la señal PWM que requiere cada servo). La idea es que con el movimiento del mouse, click derecho y click izquierdo mover los motores.

Les explico la estructura del circuito: conexiones

  • puerto B del pic ---> Registro de datos del puerto paralelo
  • puerto A del pic:
    RA0 ---> servo 1 (en el programa del micro lo llamo servogx)
    RA1 ---> servo 2 (servogy)
    RA2 ---> servo 3 (servogr)
    RA3 ---> pin10 del puerto paralelo (registro estado)
    RA4 ---> pin14 del puerto paralelo (registro estado)
  • oscilador tipo XT de 4Mhz
  • resistencias pull down en cada pin del pic

Con el movimiento del mouse en el eje x ---> mover el servo1(servogx)
Con el movimiento del mouse en el eje y ---> mover el servo2(servogy)
Con el click izquiero y derecho(mientras esten presionados) ---> mover el servo3(servogr)

El servo se mueve de 0 a 180 grados(teoricamente). En realidad se mueve un poco mas.
El intervalo de tiempo que debe estar en alto la señal PWM(ciclo de 20ms) para lograr el movimiento es de 400 a 2200 microsegundos y el resto del ciclo en bajo.

Por ejemplo para lograr que el servo se mueva 90 grados, se le deberia de enviar 50 veces el siguiente ciclo:
2200+400/2 = 1300 microsegundos en estado alto y
20000-1300 = 18700 microsegundos en estado bajo

El programa del pic:

Código: [Seleccionar]
inicio
bsf STATUS,RP0
clrf TRISA
movlw b'11111111'
movwf TRISB
bcf STATUS,RP0
movlw .130
movwf servogx
movwf servogy
movwf servogr
principal
movlw b'00000000'
movwf PORTA
movlw .100
movwf rutina
call retardo10
movlw b'00011000'
movwf PORTA
movlw .100
movwf rutina
call retardo10
movf PORTB,W
movwf servogx
movlw b'00010000'
movwf PORTA
movlw .100
movwf rutina
call retardo10
movlw b'00011000'
movwf PORTA
movlw .100
movwf rutina
call retardo10
movf PORTB,W
movwf servogy
movlw b'00001000'
movwf PORTA
movlw .100
movwf rutina
call retardo10
movlw b'00011000'
movwf PORTA
movlw .100
movwf rutina
call retardo10
movf PORTB,W
movwf servogr
movimiento
movf servogx,W
movwf rutina
incf rutina,F
movlw b'00000001'
movwf PORTA
call retardo10
movlw b'00000010'
movwf PORTA
movf servogy,W
movwf rutina
incf rutina,F
call retardo10
movlw b'00000100'
movwf PORTA
movf servogr,W
movwf rutina
incf rutina,F
call retardo10
movlw b'00000000'
movwf PORTA
movf servogx,W
sublw d'220'
movwf rutina
incf rutina,F
call retardo10
movf servogy,W
sublw d'220'
movwf rutina
incf rutina,F
call retardo10
movf servogr,W
sublw d'220'
movwf rutina
incf rutina,F
call retardo10
call retardo_bajo
goto principal

La parte principal del programa es donde leo la informacion que está en el puerto paralelo, primero le envio al puerto paralelo a traves de los pines RA3 y RA4 del pic la funcion que debe realizar el programa en C++, utilizo la instruccion inp(0x379) para leer el registro estado del puerto. Con RA3 y RA4 puedo realizar 4 combinaciones, que las establezco asi:

   RA4  RA3  RA2  RA1  RA0
b'  0      0      0      0      0  '  ----->   El programa en C++ debera hacer la funcion para el servo 1(servogx)

b'  1      0      0      0      0  '  ----->   El programa en C++ debera hacer la funcion para el servo 2(servogy)

b'  0      1      0      0      0  '  ----->   El programa en C++ debera hacer la funcion para el servo 3(servogr)

b'  1      1      0      0      0  '  ----->   El programa debera enviar el valor al registro de datos del puerto paralelo.

Comunicacion entre el micro y el puerto:

El programa del micro envia b'00000000' al puerto A, espera 1 ms, luego envia b'00011000' al puerto A, vuelve a espera 1 ms, luego lee el valor que hay en el puerto B y lo guarda en el registro servogx(servo 1). Repite lo mismo para cada servo

Envia b'00010000' al puerto A, espera 1 ms, luego envia b'00011000' al puerto A, vuelve a espera 1 ms, luego lee el valor que hay en el puerto B y lo guarda en el registro servogy(servo 2).

Envia b'00001000' al puerto A, espera 1 ms, luego envia b'00011000' al puerto A, vuelve a espera 1 ms, luego lee el valor que hay en el puerto B y lo guarda en el registro servogr(servo 3)

Programa en C++:

Código: [Seleccionar]
int main()
{
    double ix, iy;
    int mx, my, grados=130, gr=130;
    clock_t t_ini, t_fin;
    double secs, c=0.02, b=0.02;
    OpenPortTalk();
    tagPOINT posicion;
    mx = GetSystemMetrics(SM_CXSCREEN);
    my = GetSystemMetrics(SM_CYSCREEN);
    ix = (double)mx/180;
    iy = (double)my/180;
    t_ini = clock();
    while(!GetAsyncKeyState(VK_F5))
    {   
        if(inp(0x379) == 48) //Cuando el pic escribe b'00000000'
        {
            GetCursorPos(&posicion);
            grados = posicion.x/ix;
        }
        if(inp(0x379) == 56) //Cuando el pic escribe b'00010000'
        {
            GetCursorPos(&posicion);
            grados = posicion.y/iy;
        }
        if(inp(0x379) == 112) //Cuando el pic escribe b'00001000'
        {
            grados = gr;
        }
        if(inp(0x379) == 120) //Cuando el pic escribe b'00011000'
        {
            outp(0x378, grados);
        }
        t_fin = clock();
        secs = (double)(t_fin - t_ini) / CLOCKS_PER_SEC;
        if(secs > c)
        {
            if(GetAsyncKeyState(VK_LBUTTON))
                gr++;
            if(GetAsyncKeyState(VK_RBUTTON))
                gr--;
            c += 0.01;
        }
    }
    outp(0x378,130);
    return 0;
}

Cuando corro el programa y alimento el circuito funciona muy bien.. hasta que en un determinado tiempo el servo1 se empieza a mover como se tendria que mover el servo2.. y el servo2 hace la funcion del servo3 y el servo3 la del servo1 :D x_x .. ese es mi problema no se que puede estar pasando.. el microprocesador de la pc trabaja mucho mas rapido que el pic que estoy ocupando, tendria que realizar bien la lectura para cada servo.. he probado darle mas tiempo a cada lectura (4ms) pero igual me sigue pasando el mismo problema.. no puedo darle mas tiempo porque ya no tendria el refresco de 20ms que quiero :huh: o no estoy haciendo bien el protocolo de comunicacion del micro con el puerto paralelo??

Trate de explicar lo mejor que pude.. espero puedan ayudarme. Gracias!

Desconectado vlad

  • Global Moderator
  • The Communiter-
  • *
  • Mensajes: 6351
    • Qualium.net
Re: Protocolo pic16f84 - puerto paralelo
« Respuesta #1 : noviembre 13, 2010, 05:35:00 am »
En lugar de complicarte con temporizaciones tan precisas (puesto que Windows no funciona en tiempo real como un kernel RT de Linux) vas a tener siempre defases y dolores de cabeza toda la vida, y no solo eso si no también porque el LPT tiene un tiempo minimo entre cambios de modo lectura/escritura, y encima el problema es que tu PIC esta trabajando innecesariamente puesto que escanea por los tres movimientos de forma continua de manera sub-optima puesto que haces 3 cambios de contexto (lectura/escritura) sin saber si van a ser utiles.


Te recomiendo mas un protocolo asi:
  • PC envia el movimiento deseado (x,y,z) con su respectivo header que le indique al pic que servo mover (ej. x+1 =mover servo x hacia un lado y x-1 = moverlo al otro) y luego de eso parar de enviar y quedar en modo espera (leyendo LPT)
  • PIC esta en un loop de lectura del puerto y obtiene y ejecuta el movimiento deseado, una vez ejecutado le manda la señal a la PC de esta listo para que envie otro comando
  • Repetir

Esto aseguraria que ambas partes puedan trabajar a su mayor velocidad posible, porque es un mecanismo sincrono en el que no dependerias de que tu programa no pierda ninguna señal.

Esto es lo mas simple posible, pero podrias mejorarlo muchooo, como asi?, pues que la PC podria mandar todos los movimientos a ejecutar si hubo mas de uno, asi podrias hacer algo que ahorita tu codigo no puede: mover los tres ejes simultaneamente.

ejemplo si alguien mueve el mouse en diagonal seria de enviar (Ej.) x+1,y+1 y en la parte de procesamiento tu PIC ejecutaria los dos movimientos antes del .retardo10.

Tipo:
Código: [Seleccionar]
[verificar si hay movimiento para y]
movwf servogy
[verificar si hay movimiento para x]
movwf servogx
[verificar si hay movimiento para r]
movwf servogr
.retardo10

Mejorarlo aun mas seria posible añadiendo un buffer para no perder las señales de movimiento enviadas durante los ~20ms que el pic no estaria en escucha.

Desconectado smrenderos

  • MiembrosReales
  • *
  • Mensajes: 17
Re: Protocolo pic16f84 - puerto paralelo
« Respuesta #2 : noviembre 13, 2010, 01:46:14 pm »
gracias vlad por tu tiempo.

Entiendo muy bien, me dices que al registro de datos donde la pc envia la posicion a la que se tiene que mover cada servo, envie tambien a que servo le pertenece dicha informacion.

El problema es que estoy ocupando una resolucion de 1 grado para cada servo,  necesito enviarle un valor de (0 a 180) + 40 = 40 a 220, algo que solo puedo lograr con el registro completo (0 a 255), si lo realizo como me explicas perderia dos bits para el header (bit6 y bit7), y solo me quedaria un registro de 6 bits para enviar la posicion (0 a 63); con esto pierdo la resolucion de 1 grado deseada

Citar
Esto es lo mas simple posible, pero podrias mejorarlo muchooo, como asi?, pues que la PC podria mandar todos los movimientos a ejecutar si hubo mas de uno, asi podrias hacer algo que ahorita tu codigo no puede: mover los tres ejes simultaneamente.

lo estoy logrando porque en 20ms refresco la posicion de cada servo con lo que resulta el movimiento de los tres simultaneamente, al principio funciona exlente; los servos se mueven al compas del movimiento del mouse.. el problema es que cuando pasan unos 3 segundos se intercambian las señales de los servos

Desconectado chrly

  • Sv Full Member
  • *
  • Mensajes: 837
Re: Protocolo pic16f84 - puerto paralelo
« Respuesta #3 : noviembre 13, 2010, 02:38:46 pm »
y donde conseguiste los servo motor??  :shock:
Todo lo que hay que aprender...
que cosas...
asusss ordenes jefeeee. XD mi capitan ::yaoming::

Desconectado juanca

  • The Communiter-
  • *
  • Mensajes: 1112
Re: Protocolo pic16f84 - puerto paralelo
« Respuesta #4 : noviembre 13, 2010, 02:51:01 pm »
gracias vlad por tu tiempo.

Entiendo muy bien, me dices que al registro de datos donde la pc envia la posicion a la que se tiene que mover cada servo, envie tambien a que servo le pertenece dicha informacion.

El problema es que estoy ocupando una resolucion de 1 grado para cada servo,  necesito enviarle un valor de (0 a 180) + 40 = 40 a 220, algo que solo puedo lograr con el registro completo (0 a 255), si lo realizo como me explicas perderia dos bits para el header (bit6 y bit7), y solo me quedaria un registro de 6 bits para enviar la posicion (0 a 63); con esto pierdo la resolucion de 1 grado deseada

lo estoy logrando porque en 20ms refresco la posicion de cada servo con lo que resulta el movimiento de los tres simultaneamente, al principio funciona exlente; los servos se mueven al compas del movimiento del mouse.. el problema es que cuando pasan unos 3 segundos se intercambian las señales de los servos

multiplexe cuatro bits men, asi siempre tendra 8

Tus derechos comienzan donde terminan tus responsabilidades......

Desconectado vlad

  • Global Moderator
  • The Communiter-
  • *
  • Mensajes: 6351
    • Qualium.net
Re: Protocolo pic16f84 - puerto paralelo
« Respuesta #5 : noviembre 13, 2010, 03:24:32 pm »
Por cierto, respecto a tu codigo original hay un gran detalle y es que si no me equivoco con inp() estas leyendo el valor del puerto en ese preciso momento no?.

Lo que podrias hacer para apalear la desincronización seria hacer un buffer con el valor de inp() al inicio de cada loop para asegurate que al menos un movimiento se ejecutara por vez.


Te lo digo porque ahorita lo que esta pasando es:


loop
{
PIC -> b'00011000'
PC[lee puerto] -> es b'00000000'?, no, entonces continuar.
PC[lee puerto] -> es b'00001000'?, no, entonces continuar.
PIC -> b'00000000'
// Ahorita hubiera sido la oportunidad del primer valor, pero el pic ya cambio y se volvio a leer el puerto entonces nunca se va a ejecutar nada!
PC[lee puerto] -> es b'00011000'?, no, entonces continuar.
}

En cambio con el buffer seria asi:

PIC -> b'00011000'
PC[buffer] = PC[lee puerto];
loop
{
PC[buffer] -> es b'00000000'?, no, entonces continuar.
PC[buffer] -> es b'00001000'?, no, entonces continuar.
PIC -> b'00000000' // que importa, nuestro buffer mantiene el valor b'00011000'
PC[lee puerto] -> es b'00011000'?, si!, ejecutar movimiento adecuadamente.
}


Sobre todo esto te da la ventaja que vas ejecutar 3 lecturas menos al LPT por cada loop por lo que tendrá una mayor velocidad de ejecución.

Desconectado smrenderos

  • MiembrosReales
  • *
  • Mensajes: 17
Re: Protocolo pic16f84 - puerto paralelo
« Respuesta #6 : noviembre 13, 2010, 04:50:12 pm »
Citar
y donde conseguiste los servo motor??  :shock:
En el emiliani construimos un robot y me quedaron los servos que no ocupamos  ohyea: pero te dejo las tiendas donde los compramos:

RC Hobby SHOP: Centro Comercial Masferrer
Ave Masferrer Norte #408 local 8 2do. Nivel Tel. 2530-6510

Caribe Hobby Center: Centro Comercial
Plaza Suiza, Primera Planta Tel. 22246540

el precio de c/u anda por los $20, si te interesa deberias de hablar tal vez ya cuestan menos, tambien tienen miniservos.

Por cierto les dejo el proyecto que construimos con 12 servos, el pic 16f877, el 16f874 ambos a 4 Mhz y 3 matriz de led de 7x5:

[youtube]http://www.youtube.com/watch?v=YNO2iNjryYM[/youtube]

Citar
multiplexe cuatro bits men, asi siempre tendra 8
Como lo hago juanca??, hasta ahora tenia otra idea de lo que es multiplexar

Desconectado smrenderos

  • MiembrosReales
  • *
  • Mensajes: 17
Re: Protocolo pic16f84 - puerto paralelo
« Respuesta #7 : noviembre 13, 2010, 05:02:13 pm »
Citar
En cambio con el buffer seria asi:

PIC -> b'00011000'
PC[buffer] = PC[lee puerto];
loop
{
PC[buffer] -> es b'00000000'?, no, entonces continuar.
PC[buffer] -> es b'00001000'?, no, entonces continuar.
PIC -> b'00000000' // que importa, nuestro buffer mantiene el valor b'00011000'
PC[lee puerto] -> es b'00011000'?, si!, ejecutar movimiento adecuadamente.
}
Vlad y para actualizar el contenido del PC[buffer], en que parte del codigo vuelvo hacer PC[buffer] = PC[lee puerto]? si lo hiciera en el loop vuelvo al mismo problema o me equivoco?

Desconectado Jaru

  • The Communiter-
  • *
  • Mensajes: 13252
  • some text
Re: Protocolo pic16f84 - puerto paralelo
« Respuesta #8 : noviembre 13, 2010, 05:40:52 pm »
-usar el puerto serie en lugar del paralelo?

-programar el PIC en C o Basic para mejor control

-Enviar textualmente posicion y comandos y hacer en el pic algo asi como una consola?

-programar el pic en C o basic para un programa tan simple no seria mejor?

-usar interrupciones en lugar de polling?

-Usar un PIC que tenga el modulo PWM en lugar de estarlo implemententando en software. (sugiero el 16f627)


asi como te dice Vlad, se siente que te complicas mucho pudiendo hacer las cosas distintas.

tengo años de experiencia en programacion de microcontroladores PIC, si necesitas sugerencia me podes preguntar  :thumbsup:
N/A

Desconectado vlad

  • Global Moderator
  • The Communiter-
  • *
  • Mensajes: 6351
    • Qualium.net
Re: Protocolo pic16f84 - puerto paralelo
« Respuesta #9 : noviembre 13, 2010, 06:18:07 pm »
Vlad y para actualizar el contenido del PC[buffer], en que parte del codigo vuelvo hacer PC[buffer] = PC[lee puerto]? si lo hiciera en el loop vuelvo al mismo problema o me equivoco?

Si me equivoqué!, sería al principio del loop que se carga PC[buffer].

@naruto: en el caso de el que ya tiene todo montado creo que seria muy conveniente que optimizara lo que ya tienen en lugar de incurrir mas gastos a menos que significara una mejora sustancial!, pues creo que aun por software con lo que tiene puede bastar para el fin que busca.

Lo de las interrupciones es una magnifica idea por cierto, lastima que el PIC16F84 solo admita una interrupcion a la vez, digo, como para usar un RB por servo, pero igual podria utilizarse solo una como trigger para toda la operación :)

Desconectado Jaru

  • The Communiter-
  • *
  • Mensajes: 13252
  • some text
Re: Protocolo pic16f84 - puerto paralelo
« Respuesta #10 : noviembre 13, 2010, 06:29:58 pm »
Si me equivoqué!, sería al principio del loop que se carga PC[buffer].

@naruto: en el caso de el que ya tiene todo montado creo que seria muy conveniente que optimizara lo que ya tienen en lugar de incurrir mas gastos a menos que significara una mejora sustancial!, pues creo que aun por software con lo que tiene puede bastar para el fin que busca.

Lo de las interrupciones es una magnifica idea por cierto, lastima que el PIC16F84 solo admita una interrupcion a la vez, digo, como para usar un RB por servo, pero igual podria utilizarse solo una como trigger para toda la operación :)

con una interrupcion es mas que suficiente, que mande el pic a dormir (no me acuerdo si el 84 podia hacer eso) y que se despierte a atender la peticion de la PC con la interrupcion.

si ya tiene el puerto paralelo, pues, ni modo.
programar el PIC de forma distinta es una posibilidad tambien.
N/A

Desconectado vlad

  • Global Moderator
  • The Communiter-
  • *
  • Mensajes: 6351
    • Qualium.net
Re: Protocolo pic16f84 - puerto paralelo
« Respuesta #11 : noviembre 13, 2010, 07:11:45 pm »
con una interrupcion es mas que suficiente, que mande el pic a dormir (no me acuerdo si el 84 podia hacer eso) y que se despierte a atender la peticion de la PC con la interrupcion.

si ya tiene el puerto paralelo, pues, ni modo.
programar el PIC de forma distinta es una posibilidad tambien.

Si se puede pero umm creo que no valdria la pena hacerlo dormir por un par de milisegundos entre instrucciones :)

Desconectado smrenderos

  • MiembrosReales
  • *
  • Mensajes: 17
Re: Protocolo pic16f84 - puerto paralelo
« Respuesta #12 : noviembre 13, 2010, 07:48:56 pm »
Vlad: probare lo que me dices, en un rato comento como me fue

con una interrupcion es mas que suficiente, que mande el pic a dormir (no me acuerdo si el 84 podia hacer eso) y que se despierte a atender la peticion de la PC con la interrupcion.

si ya tiene el puerto paralelo, pues, ni modo.
programar el PIC de forma distinta es una posibilidad tambien.

Que ondas naruto, fijate que si ya tengo todo montado, y en la U nos pidieron que interactuaramos con el puerto paralelo, no hay problema con la programacion del micro; tengo armado un programador basado en el JDM en la bredboard que estoy trabajando, hasta ahora he programado el pic unas 15 veces haciendo pruebas. Como harias un protocolo de comunicacion entre lpt(Dev-C++) <---> pic(asm)??

No tengo mucha experiencia con los pic, manejo lo basico, retardos, bucles y las ganas de seguir aprendiendo mas. Si me pudieran explicar el funcionamiento de las interrupciones seria bienvenido  :sur:, solo sé que el 16f84 tiene 4 fuentes de interrupcion(googleada  :phew:).. mi otro problema es el tiempo, el miercoles tengo que entregar un avance, hasta ahora casi lo tengo hecho, solo me he topado con el problema del protocolo lpt-pic. Un servo funciona de toke, claro que si solo le envio una señal por el puerto, casi lloro  :cry: cuando el servo se movia al compas del mouse :).

Lo otro que tengo pensado hacer es modificar el programa del micro y darle mas tiempo a la lectura, unos 100 ms en cada una, ya no tendria el refresco de 20ms para la posicion de cada servo, pero ni modo tal vez con esto se soluciona, aunque con lo de vlad espero que funcione  :thumbsup:..

Gracias de nuevo Vlad y naruto por su tiempo!


Desconectado Jaru

  • The Communiter-
  • *
  • Mensajes: 13252
  • some text
Re: Protocolo pic16f84 - puerto paralelo
« Respuesta #13 : noviembre 13, 2010, 08:23:29 pm »
que bueno que ya casi lo tenes hecho.

en que universidad te dejan eso?
vas a seguir haciendo proyectos con pic?

te recomiendo que aprendas a programar el pic usando el mikroC
[youtube]http://www.youtube.com/watch?v=DeezlaooclY&feature=related[/youtube]

por ahi tengo un LCD de un nokia 3310 que ya simule y puedo interfacear con el PIC, si te sirve eso para algun proyecto decime


N/A

Desconectado smrenderos

  • MiembrosReales
  • *
  • Mensajes: 17
Re: Protocolo pic16f84 - puerto paralelo
« Respuesta #14 : noviembre 13, 2010, 10:57:35 pm »
vlad: ha mejorado   :yahoo: pero ahora tiemblan los motores, como que tomaran una lectura diferente en un intervalo de tiempo bien corto, dejo como queda el codigo en C++

Código: [Seleccionar]
while(!GetAsyncKeyState(VK_F5))
    {
        buffer = inp(0x379);   
        if(buffer == 48)
        {
            GetCursorPos(&posicion);
            grados = posicion.x/ix;
        }
        if(buffer == 56)
        {
            GetCursorPos(&posicion);
            grados = posicion.y/iy;
        }
        if(buffer == 112)
        {
            grados = gr;
        }
        if(buffer == 120)
        {
            outp(0x378, grados);
        }
        /*t_fin = clock();
        secs = (double)(t_fin - t_ini) / CLOCKS_PER_SEC;
        if(secs > c)
        {
            if(GetAsyncKeyState(VK_LBUTTON))
                gr++;
            if(GetAsyncKeyState(VK_RBUTTON))
                gr--;
            c += 0.01;
        }*/
    }

gracias vlad.. vere si le puedo dar mas tiempo a la lectura

que bueno que ya casi lo tenes hecho.

en que universidad te dejan eso?
vas a seguir haciendo proyectos con pic?

En la ues.. nos pidieron un proyecto que interactuara con el puerto paralelo, y pues tenia 4 servos y el 16f84.. y  con eso resulto un proyecto de controlar el movimiento de una webcam(eje x, eje y, rotarla)  :)
Estaria interesante realizar un proyecto sobre vision artificial y micros.. el tratamiento de imagen en un microcontrolador.. algun robot con vision artificial