Duda con el PIC18F4550 y sentencia "Switch"

Hola, amigos del foro.
Soy nuevo por aquí. (Sólo preguntando, porque siempre he despejado mis dudas en este foro.)

Resulta que estoy tratando de armar un brazo robótico de 6 grados de libertad y me encuentro aprendiendo sobre servomotores.
He buscado mucho en la web y es difícil encontrar un PIC que maneje las 6 salidas que yo quiero, por lo que he optado por generar mi señal PWM por medio de retardos, y hasta ahora he logrado mover el motor. (Un poco lento, ya verán por qué)

Quiero hacer una rutina por medio de la sentencia Switch para seleccionar el motor que quiero mover y que se ejecute el programa y así sucesivamente desde motor 1 hasta el 6, y al programar hago que el PIC reconozca el número del motor mediante un teclado matricial, pero al querer moverlo no sucede nada.

¿Alguien podría decirme qué estoy haciendo mal?
Me considero en un nivel intermedio programando y aprendo rápido, pero aquí estoy un poco atorado.

Mi código es el siguiente:
PHP:
#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;
char Motor;
char Numero;
int Num;

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

printf(lcd_putc, "Esperando Tecla");
while(true)
{
Numero = kbd_getc();
if(Numero != 0){
printf(lcd_putc, "\fPresionado. %c", Numero);
}
Num=atoi(motor);
switch(motor){
case 1:
if(motor ==1){
{
/*Mover hacia la Derecha*/
while(true){
if(input_state(pin_c0)==1){
duty++;
output_high(PIN_C2);
delay_us(duty);           //Mandamos un pulso de 1.5 ms para mover el servo a 0º
output_low(PIN_C2);
delay_us(20000-duty);

}
/*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 demás y funciona bien, algo lento ya que la variable duty se incrementa de 1 en 1.

Espero puedan ayudarme, o proponer como podría mover los 6 servos, ya que no encuentro un PIC con 6 módulos PWM o CCP, como el 18F4550 creo que sólo tiene 2.


Saludos.
 
Última edición por un moderador:
¿Si ya usas la sentencia "Switch", para qué realizas otra comparación con la sentencia "If" sobre la misma variable?
O sea, en esta parte de programa:
Código:
switch(motor){
case 1:
if(motor ==1){
{
...
El caso "1" ya decide que "motor" es 1, y el If(motor == 1) también, por lo cual es redundante esa parte del programa.
Hacer eso no genera conflictos, pero no tiene sentido y esas instrucciones de sobra consumen RAM.
Espero puedan ayudarme, o proponer como podría mover los 6 servos, ya que no encuentro un PIC con 6 módulos PWM o CCP
Puede ser que el proceso para controlar 6 servos te funcione bien si usas RTOS.
 
Hola. Muchísimas gracias por contestar. Revisaré el tema que me comentas.
Y pues sí, después de un tiempo me di cuenta que estaba utilizando cosas sin sentido, por lo que opté por la sentencia goto, que me está funcionando mejor:

He aquí el nuevo código:
PHP:
#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);
}
Me está funcionando bien, aunque aún debo terminar el menú para controlar los motores, por lo que aún hay variables sin usar.

Ahora el detalle es ver como me funciona mejor controlarlos, si como lo estoy haciendo o como me dices.
Esperemos tener resultados pronto y con gusto compartiré la experiencia.
 
Última edición por un moderador:
tambien el PWM a software no es una idea descabellada usando un delay como base de tiempo si no sabes hacer interrupciones

lo que puedes hacer es un delay hasta el final del while(1) para hacer una base de tiempo ejemplo

while(1)
{

//codigo
delay_us(50);
contador++;
}

ahora para hacer PWM necesitamos ciclo de trabajo y una frecuencia fija en el servomotor creo que el periodo son 20ms

entonces digamos que para hacer el periodo no hare calculos pero mas o menos va asi


usaremos una variable que incremente cuando pase de un sierto numero esta variable se reseteara con 0 es decir con esto fijamos nuestra frecuencia.


unsigned char contador;

while(1)
{
if(contador>=255)
{
contador=0;
}


delay_us(50);
contador++;

}

ya tenemos una frecuencia totalmente FIJA ahora lo que falta es hacer el ciclo de trabajo para cada pin de nuestro micro eso es muy facil
if else es lo que se necesita

unsigned char contador;
unsigned char ciclo;

while(1)
{
if(contador>=255)
{
contador=0;
}



if(contador>=ciclo)
{
output_high(pin_b1);
}
else
{
output_low(pin_b1);
}



delay_us(50);
contador++;

}


y si queremos mas pines repetimos la misma accion!


unsigned char contador;
unsigned char ciclo;
unsigned char ciclo1;
unsigned char ciclo2;

while(1)
{
if(contador>=255)
{
contador=0;
}



if(contador>=ciclo)
{
output_high(pin_b0);
}
else
{
output_low(pin_b0);
}


if(contador>=ciclo1)
{
output_high(pin_b1);
}
else
{
output_low(pin_b1);
}


if(contador>=ciclo2)
{
output_high(pin_b2);
}
else
{
output_low(pin_b2);
}




delay_us(50);
contador++;

}

y asi sucecivamente obviamente debes calcular el periodo yo puse 255 por rapidez

pero divide 20ms entre 255 y eso te da el tiempo del delay
 
Última edición:
tambien el PWM a software no es una idea descabellada usando un delay como base de tiempo si no sabes hacer interrupciones

lo que puedes hacer es un delay hasta el final del while(1) para hacer una base de tiempo ejemplo

while(1)
{

//codigo
delay_us(50);
contador++;
}

ahora para hacer PWM necesitamos ciclo de trabajo y una frecuencia fija en el servomotor creo que el periodo son 20ms

entonces digamos que para hacer el periodo no hare calculos pero mas o menos va asi


usaremos una variable que incremente cuando pase de un sierto numero esta variable se reseteara con 0 es decir con esto fijamos nuestra frecuencia.


unsigned char contador;

while(1)
{
if(contador>=255)
{
contador=0;
}


delay_us(50);
contador++;

}

ya tenemos una frecuencia totalmente FIJA ahora lo que falta es hacer el ciclo de trabajo para cada pin de nuestro micro eso es muy facil
if else es lo que se necesita

unsigned char contador;
unsigned char ciclo;

while(1)
{
if(contador>=255)
{
contador=0;
}



if(contador>=ciclo)
{
output_high(pin_b1);
}
else
{
output_low(pin_b1);
}



delay_us(50);
contador++;

}


y si queremos mas pines repetimos la misma accion!


unsigned char contador;
unsigned char ciclo;
unsigned char ciclo1;
unsigned char ciclo2;

while(1)
{
if(contador>=255)
{
contador=0;
}



if(contador>=ciclo)
{
output_high(pin_b0);
}
else
{
output_low(pin_b0);
}


if(contador>=ciclo1)
{
output_high(pin_b1);
}
else
{
output_low(pin_b1);
}


if(contador>=ciclo2)
{
output_high(pin_b2);
}
else
{
output_low(pin_b2);
}




delay_us(50);
contador++;

}

y asi sucecivamente obviamente debes calcular el periodo yo puse 255 por rapidez

pero divide 20ms entre 255 y eso te da el tiempo del delay

Wow es parecido a lo que estoy utilizando, lo voy a poner en practica haber que tal me va, ahorita estoy trabajando en ello por lo que estare posteando si hay algun tope.

Gracias a todos por sus respuestas
 
El pic16f887 tiene dos modulos CCP, pero en modo PWM puede tener hasta 4 salidas, checa el datasheet, del PIC16F887 la pagina 134 hacia abajo. No se si el PIC18F4550 tenga la misma configuración.

y si no es suficiente puedes conectar 2 pics mediante USART o I2C o SPI, y asi el código será más sencillo y 2 pics chicos como el PIC18F2550 o el PIC16F886 y los cuales son de 28 pines, solo que no contienen el puerto D y E. pero conservan los modulos ADC, USART, CCP entre otros.
 
no esas son marranadas poner varios micros para varios PWM

generalmente cuando tienes un apelotonamiento la PCB se complica , lo que queda es emular el hardware con software

lo que puse es PWM generado con software.

si tiene sus obvias limitaciones pues el hardware esta optimizado
y como sabemos el pic a sus cortas intrucciones en ASM cuando esta en C le lleva varios ciclos de reloj hacer un algoritmo.

lo que nuestro micro es lento.

generar PWM a software es bueno para manejar luces , motores , servos. pero la limitacion se ve al generar audio ahi es cuando empieza a quedarse corto.

cuando se desea generar audio con PWM aqui si es conveniente usar el hardware del micro
 
Hola buenas soy nuevo en este foro de electrónico hoy vengo consultando una duda con un micro y una programación en c.
Resulta que estoy haciendo unos proyectos de iluminaria led, realice una programación con swich case y la cargue en el PIC18F4550. La programación funciona a la perfección en este micro. Solo estoy usando 3 puertos A para los leds y 1 Puerto en el A para un pulsador que va cambiando los efectos programados con los case.
Ahora bien cambio de micro por uno mas chico y económico que es el 12F675 hago la misma programación y en los mismos puertos, pero no me responde correctamente ya que no cambia los case. En Proteus cuando simuló se ve que cuando presiono el pulsador se activa el puerto pero los otros de los leds no hacen nada.
Si llegaron hasta aquí gracias por escuchar y si podrían ayudar seria genial gracias. Dejo adjunto en rar el proteus y la programacion.
 

Adjuntos

  • Simulaciones.rar
    35.5 KB · Visitas: 2
  • proteus.jpg
    proteus.jpg
    359.8 KB · Visitas: 4
Yo veo que en el esquema tienes conectado el pin GP4 al pulsador, pero en el código tienes declarado el pin GP3

Si nada más requieres esas dos rutinas el código se puede resumir bastante.

Así funcionaría mejor:

C:
#include <12f675.h>
#use delay (INTERNAL = 4 MHz)

void Efecto1 (void);
void Efecto2 (void);

#define pulsador    PIN_A4

void main (void)
{
    int contador = 0;
  
    while(TRUE)
    {
        if (input_state(pulsador))
        {
            contador ++;
          
            while (input_state(pulsador));
        }
          
        if (contador > 1)    contador = 0;
  
        switch (contador)
        {
            case 0:
                Efecto1();
                break;
            case 1:
                Efecto2();
        }
    }
}

void Efecto1 (void)
{
    output_a(0b111);
}

void Efecto2 (void)
{
   output_a(0b000);
}
Pero de cualquier forma es mucha vuelta para esas dos rutinas.
 
Yo veo que en el esquema tienes conectado el pin GP4 al pulsador, pero en el código tienes declarado el pin GP3

Si nada más requieres esas dos rutinas el código se puede resumir bastante.

Así funcionaría mejor:

C:
#include <12f675.h>
#use delay (INTERNAL = 4 MHz)

void Efecto1 (void);
void Efecto2 (void);

#define pulsador    PIN_A4

void main (void)
{
    int contador = 0;
 
    while(TRUE)
    {
        if (input_state(pulsador))
        {
            contador ++;
         
            while (input_state(pulsador));
        }
         
        if (contador > 1)    contador = 0;
 
        switch (contador)
        {
            case 0:
                Efecto1();
                break;
            case 1:
                Efecto2();
        }
    }
}

void Efecto1 (void)
{
    output_a(0b111);
}

void Efecto2 (void)
{
   output_a(0b000);
}
Pero de cualquier forma es mucha vuelta para esas dos rutinas.
Muchas gracias funciono perfectamente, Que error mio no darme cuenta que estaba mal el puerto especificado. porque leia AN3 y crei que era ese puerto. Si de igual manera voy a agregar mas efectos, solo tenia puestos 2 para probar
 
Atrás
Arriba