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:
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++:
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
.. 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
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!