Haz una pregunta
  Foros de Electrónica » Diseño digital » Microcontroladores y sistemas embebidos
Foros Registrarse ¿Olvidaste tu contraseña?

Temas similares

16/06/2015 #1

Avatar de Cloudff7

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:
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>

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.
16/06/2015 #2
Moderador

Avatar de D@rkbytes

¿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.
Cloudff7 dijo: Ver Mensaje
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.
16/06/2015 #3

Avatar de Cloudff7

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:
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.
16/06/2015 #4

Avatar de Gudino Roberto duberlin

Hola, debes considerar utilizar interrupciones cómo base de retardos, ya que la función delay_XX, consume tiempo inaprovechable para otra tarea.
16/06/2015 #5

Avatar de TRILO-BYTE

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
17/06/2015 #6

Avatar de Cloudff7

TRILO-BYTE dijo: Ver Mensaje
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
17/06/2015 #7

Avatar de ruben90

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.
18/06/2015 #8

Avatar de TRILO-BYTE

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
Respuesta
¿Tienes una mejor respuesta a este tema? ¿Quieres hacerle una pregunta a nuestra comunidad y sus expertos? Registrate

Foros de Electrónica » Diseño digital » Microcontroladores y sistemas embebidos

Powered by vBulletin® Version 3.8.4
Copyright ©2000 - 2017, Jelsoft Enterprises Ltd.
Search Engine Optimization by vBSEO ©2011, Crawlability, Inc.