Autor Tema: Duda con Senstencias CCS y PIC18f4550  (Leído 2590 veces)

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

Desconectado Cloudff7

  • PIC10
  • *
  • Mensajes: 5
Duda con Senstencias CCS y PIC18f4550
« en: 16 de Junio de 2015, 18:54:24 »
Hola, amigos del foro
Soy nuevo por aquí(solo preguntando por que siempre he despejado mis dudas en este foro)
resulta que estoy tratando de armar un brazo Robotico de 6 grados de libertad y me encuentro aprendiendo sobre servomotores
he buscado mucho en la web y es difícil un PIC que te maneje las 6 salidas que yo quiero, por lo que he optado por general mi señal PWM
por medio de delays, y hasta ahora le logrado mover el motor(un poco lento ya verán por que).
y quiero hacer una rutina por medio de la sentencia Switch para seleccionar el motor que quiero mover y que se ejecute el programa
y asi sucesivamente desde motor 1 hasta el 6, pero la programar hago que el pic reconozca el numero del motor mediante un teclado matricial pero al querer moverlo lo sucede nada

¿alguien podrias decirme que estoy haciendo mal?, me considero en un nivel intermedio programando y aprendo rápido pero aquí estoy un poco atorado

Mi codigo el es Siguiente
#include <18F4550.h>
#FUSES HSPLL,NOPROTECT, NODEBUG,NOWRT,MCLR,PLL5
#use delay(clock=20000000)
#include "kbd_lib.c"
#include <lcd.c>
#include <stdlib.h>

int16 duty=1500; // comienzo dandole un valor a mi variable duty que da un pulso de 1.5ms(1500us)
char Motor;
char Numero;
int Num;

void main (){
kbd_init();
lcd_init();

printf(lcd_putc, "Esperando Tecla");                  //espero el numero de motor a mover
while(true)
{
Numero = kbd_getc();                                  //obtiene el dato
if(Numero != 0){                                         //mientras sea diferente de 0
printf(lcd_putc, "\fPresionado. %c", Numero); //motor seleccionado
 ///////////////Esta rutina debe mover el motor que seleccione arriba///////////////////////
}
Num=atoi(motor);
switch(motor){
case 1:
if(motor ==1){
{
/*Mover hacia la Derecha*/
while(true){
if(input_state(pin_c0)==1){             //mientras el pin C0 este presionado
duty++;                                        //Se incrementa la variable duty
output_high(PIN_C2);                      //Pone el alto el pin C2
delay_us(duty);                              //e incrementa el ancho de pulso mientras el boton este en alto
output_low(PIN_C2);                       //Pone el pin en bajo hasta
delay_us(20000-duty);                    //acompletar los 20 ms (50Hz) que es la señal que debe mandarse al pic

}
/*Mover hacia la Izquierda*/
if(input_state(pin_c1)==1){
duty--;
output_high(PIN_D2);
delay_us(duty);           //Mandamos un pulso de 1.5 ms para mover el servo a 0º
output_low(PIN_D2);
delay_us(20000-duty);
break;
}
}
}
}
}
}
}



Cabe resaltar que he usado la rutina para mover el motor sin todo lo demas y funciona bien, algo lento ya que la variable duty se incrementa de 1 en 1.

Espero puedan ayudarme, o proponer como podria mover los 6 servos ya que no encuentro un pic con 6 modulos PWM o CCP como el 18F4550 creo que solo tiene 2

Saludos

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re: Duda con Senstencias CCS y PIC18f4550
« Respuesta #1 en: 16 de Junio de 2015, 19:25:24 »
Como supones tenes que hacer un PWM por software, Ya hay varios temas hablando de esos, creo que una busqueda en el foro y vas a encontrar muchos.
Ahi vas tener que tener una base de tiempo como un timer y su correspondiente interrupcion.

Luego en tu programa principal si manejas tu teclado y las variables del pwm.

Cosas por la cual veo que tu programa no puede funcionar como queres:

Num=atoi(motor);
switch(motor){

"motor" en ese caso es un char... es decir una letra... pero una letra esta representada por 8 bits , es igual a un entero, por lo cual podes usarlo ahi... la instruccion de arriba no tiene sentido ya que no lo usarias.
El tema luego viene cuando haces:

case 1:

En donde 1, no es lo mismo que '1' , es decir 1 = 0x01 y '1' = 0x31 = 49, si pones case '1': ahi va a funcionar ya que compararia la salida del char motor ( en caso que se presione 1 este contiene un caracter '1' o valor 0x31 )
No hay un valor default, deberias ponerlo siempre.

Y pienso que esta linea es redundante que ya lo estaria haciendo el case '1', y ademas esta mal por lo mismo de arriba:
if(motor ==1)

Por otra parte una ves que entro a el
while(true){

NO sale mas. solo saldria si presionas RC1, por el break; lo cual faltaria nuevamente otro break; para el case. pero en caso de ir hacia la derecha se quedaria para siempre ahi. en caso de la izquierda haria un solo paso.
Esto si haces un PWM por soft con interrupciones te lo ahorrarias, ya que solo manejarias que cada ves que entre simplemente incremente en 5 por ejemplo la variable pwm1(correspondiente al motor1) y listo.
Ademas no tendrias ningun delay. Y estaria constantemente corriendo el PWM, sin necesidad de tu interaccion, y vos solo manejarias el duty por asi decirlo.
« Última modificación: 16 de Junio de 2015, 19:28:23 por KILLERJC »

Desconectado Cloudff7

  • PIC10
  • *
  • Mensajes: 5
Re: Duda con Senstencias CCS y PIC18f4550
« Respuesta #2 en: 16 de Junio de 2015, 20:50:27 »
Como supones tenes que hacer un PWM por software, Ya hay varios temas hablando de esos, creo que una busqueda en el foro y vas a encontrar muchos.
Ahi vas tener que tener una base de tiempo como un timer y su correspondiente interrupcion.

Luego en tu programa principal si manejas tu teclado y las variables del pwm.

Cosas por la cual veo que tu programa no puede funcionar como queres:

Num=atoi(motor);
switch(motor){

"motor" en ese caso es un char... es decir una letra... pero una letra esta representada por 8 bits , es igual a un entero, por lo cual podes usarlo ahi... la instruccion de arriba no tiene sentido ya que no lo usarias.
El tema luego viene cuando haces:

case 1:

En donde 1, no es lo mismo que '1' , es decir 1 = 0x01 y '1' = 0x31 = 49, si pones case '1': ahi va a funcionar ya que compararia la salida del char motor ( en caso que se presione 1 este contiene un caracter '1' o valor 0x31 )
No hay un valor default, deberias ponerlo siempre.

Y pienso que esta linea es redundante que ya lo estaria haciendo el case '1', y ademas esta mal por lo mismo de arriba:
if(motor ==1)

Por otra parte una ves que entro a el
while(true){

NO sale mas. solo saldria si presionas RC1, por el break; lo cual faltaria nuevamente otro break; para el case. pero en caso de ir hacia la derecha se quedaria para siempre ahi. en caso de la izquierda haria un solo paso.
Esto si haces un PWM por soft con interrupciones te lo ahorrarias, ya que solo manejarias que cada ves que entre simplemente incremente en 5 por ejemplo la variable pwm1(correspondiente al motor1) y listo.
Ademas no tendrias ningun delay. Y estaria constantemente corriendo el PWM, sin necesidad de tu interaccion, y vos solo manejarias el duty por asi decirlo.

Gracias me arme otro programa con un mejor menu para seleccionar el motor que voy a mover y hasta ahorita me funciona bien,
Eso de las interrupciones ya lo habia leido pero me confunde un poco, investigare en el foro como me comentas haber que encuentro

entonces crees que con las interrupciones pueda manejar los 6 Motores? y sio es asi serian dependientes o independientes?

Saludos y perdona si mi pregunta fue algo confusa aun debo acostumbrarme a ordenas mis ideas.

Desconectado Cloudff7

  • PIC10
  • *
  • Mensajes: 5
Re: Duda con Senstencias CCS y PIC18f4550
« Respuesta #3 en: 16 de Junio de 2015, 20:52:47 »
mira este es mi nuevo código, aun me falta terminar el menú pero hasta ahora anda bien
#include <18F4550.h>
#FUSES HSPLL,NOPROTECT, NODEBUG,NOWRT,MCLR,PLL5
#use delay(clock=20000000)
#include "kbd_lib.c"
#include <lcd.c>
#include <stdlib.h>
#define M PIN_E0 // MENU
#define A PIN_A0 // Motor 1
#define B PIN_A1 // Motor 2
#define C PIN_A2 // Motor 3
#define D PIN_A3 // Motor 4
#define E PIN_A4 // Motor 5
#define F PIN_A5 // Motor 6

int x;
int16 duty=1500;
char Motor;
char Numero;

void main(void){

    lcd_init();
            delay_ms(1000);
            lcd_gotoxy(1,1);
            lcd_putc("   BIENVENIDO");
                delay_ms(1000);
        for (x=0;x<=2;++x){
            lcd_gotoxy(1,2);
            lcd_putc("CARGANDO SISTEMA");
                delay_ms(400);
            lcd_gotoxy(1,2);
            lcd_putc("----------------");
                delay_ms(400);
        }goto MENU;
        //-----------------------------LCD MENU-------------------------------//
MENU:
        do{
            lcd_gotoxy(1,1);
            lcd_putc("      MENU      ");
            lcd_gotoxy(1,2);
            lcd_putc("   MOTOR BASE      ");
            delay_ms(1000);
            lcd_gotoxy(1,2);
            lcd_putc("   MOTOR BRAZO      ");
            delay_ms(1000);
            lcd_gotoxy(1,2);
            lcd_putc("   MOTOR CODO      ");
            delay_ms(1000);
    if (input(A)){
        goto MOTORBASE;
    }
        }while(TRUE);
   

MOTORBASE:
do{
if (input(M)){
goto MENU;
}
 
lcd_gotoxy(1,1);
lcd_putc(" MOVIENDO      ");
lcd_gotoxy(1,2);
lcd_putc(" MOTOR BASE      ");



while(true){                                 /*Mover hacia la Derecha*/
if(input_state(pin_b1)==1){
duty++;
output_high(PIN_C0);
delay_us(duty);           //Mandamos un pulso de 1.5 ms para mover el servo a 0º
output_low(PIN_C0);
delay_us(20000-duty);

}
/*Mover hacia la Izquierda*/
if(input_state(pin_b2)==1){
duty--;
output_high(PIN_C0);
delay_us(duty);           //Mandamos un pulso de 1.5 ms para mover el servo a 0º
output_low(PIN_C0);
delay_us(20000-duty);

}
 if (input(M)){
        goto MENU;
 }
}

 }while(TRUE);
}

Si ves variables que no estan siendo usadas es por que aun falta terminar el menú y el control de cada motor, por lo que debera agregar o quitar avriables segun me convenga.

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re: Duda con Senstencias CCS y PIC18f4550
« Respuesta #4 en: 16 de Junio de 2015, 23:14:52 »
La interrupcion es algo que corta el flujo normal del programa..

Suponete esta situacion, vos estas encendiendo un led, 5 segundos apagado y 5 segundos encendido.
Pero ademas queres que apenas se presione 1 boton encienda/apague otro led, Sin interrupciones lo mas simple seria hacer esto:

(Las funciones no son correctas es solo para dar el ejemplo)
Código: C
  1. while(1)
  2. {
  3. led = 1;
  4. delay(5s);
  5. led=0;
  6. delay(5s);
  7. if ( boton=1 ) {otroled = !otroled;}
  8. }

Pero si por ejemplo presionas el boton cuando esta en la instruccion led=1; vas a tener que tener presionado el boton 10s para que recien llegue al if y entre.. Solucion mas simple y mas rapida? Preguntar mas veces,, le agrego el mismo if del final despues del primer delay

Código: C
  1. led = 1;
  2. delay(5s);
  3. if ( boton=1 ) {otroled = !otroled;}
  4. led=0;
  5. delay(5s);
  6. if ( boton=1 ) {otroled = !otroled;}

Bien pero ahora tengo que esperar 5s.. es menos pero todavia no es exacto, y asi puedo dividir mi delay en 5 delays de 1 segundo y preguntar en cada uno de ellos, pero aun asi no es lo suficientemente rapido
Ahora si usas una interrupcion ( por ejemplo el puerto B suele tener interrupcion y conectas el boton a uno de esos pines) no importa tu programa principal, ya que apenas ocurre la interrupcion este deja el programa que estaba corriendo, ejecuta el programa de interrupcion y vuelve a donde habia dejado, esto casi inmediatamente

Código: C
  1. interrupt()
  2. {
  3. if ( boton=1 ) {otroled = !otroled;}
  4. }
  5.  
  6. main()
  7. {
  8. led = 1;
  9. delay(5s);
  10. led=0;
  11. delay(5s);
  12. }

Entonces esta ves, por mas que este en el delay o lo que sea, va a entrar rapidamente a mi interrupcion, es decir rompo con el flujo del programa y luego vuelvo.

Ahora que aplicacion puede tener esto en tu programa ?
Podes usar un timer, el timer usa un registro de tamaño fijo, algunos de 8 y otros de 16 bits. el de 8 solo puede contar hasta 255( 0xFF o 1111 1111 ), cuando suma 1 mas ocurre un overflow, y se pone a 0, ese overflow es captado y activa la bandera de interrupcion, lo que si activaste la interrupcion del timer va a hacer el codigo de la interrupcion.
El timer permite crear una medida de tiempo, ya que sabes cuanto tarda cada ciclo de reloj dentro del PIC, por ejemplo si el ciclo tarda 10us y vos contas 100 para que se produzca el overflow, eso quiere decir que paso 1ms.

Ahora imaginate la señal PWM en el tiempo. Por ejemplo el servo es de 20ms, si haces un PWM de 256 pasos ( 8 bits ) eso quiere decir que tenes que hacer algo que cada 78.12us se ejecute para cambiar las salidas. Entonces usar tu timer para que haga una interrupcion en ese tiempo. Luego contas cuantas veces entro a la interrupcion, cuando llega a 256 quiere decir que ya pasaron los 20ms,  Entonces lo que falta es tener las variables de cada PWM, si necesitas 1.5ms eso quiere decir que deberia contar 19 (1.5ms / 78.12us ) entonces en tu interrupcion preguntas si el contador es mayor o menor que lo que deberia contar, si es menor que ponga a 1 la salida, si es mayor que la ponga a 0.

No se si te la compique, pero si ves un codigo estoy seguro que vas a entenderlo mejor

Desconectado Cloudff7

  • PIC10
  • *
  • Mensajes: 5
Re: Duda con Senstencias CCS y PIC18f4550
« Respuesta #5 en: 09 de Julio de 2015, 19:52:17 »
Muchas Gracias
KILLERJC

M;e lo has explicaod muy claro y voy a ponerlo en practica