Autor Tema: señal con frecuencia variable  (Leído 3077 veces)

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

Desconectado badtzdizzy

  • Colaborador
  • PIC16
  • *****
  • Mensajes: 234
señal con frecuencia variable
« en: 08 de Septiembre de 2004, 17:43:00 »
Hola de nuevo

Pues ahora me encuentro realizando un programa para generar una señal cuadrada con frecuencia variable. Mi problema está en que no me está pelando los cambios de estado, solo me manda una señal con frecuencia constante por el pin A0. Lo que estoy haciendo es utilizar tres push buttons en los pines B4,B5 y B6, controlando incremento, decremento y posición numérica (unidad, decena, centena y millar) respectivamente. Pero no se que estoy haciendo mal, este es el código que hice:
Codigo:

#include <16f874A.h>
#fuses HS,NOWDT,NOPROTECT  //define los fusibles que se deben poner en al parte al momento de programar
#use delay(clock=20000000)  //le dice al compilador la velocidad del procesador y habilita el uso de las funciones delay_ms() and delay_us(). La velocidad es en ciclos por segundo

int cuenta=0;
int valor=9;
int u=0;
int d=0;
int c=0;
int m=0;


void flash_led_up()
{
   output_low(PIN_A0);
   delay_ms(u);
   delay_ms(d*10);
   delay_ms(c*100);
   delay_ms(m*1000);
   output_high(PIN_A0);
   delay_ms(u);
   delay_ms(d*10);
   delay_ms(c*100);
   delay_ms(m*1000);
}

main()  
{
set_tris_a(0x00);
set_tris_b(0xFF);
port_b_pullups(TRUE);

while (TRUE)
{
flash_led_up();
if (!input(PIN_B4))
   {
      delay_ms(50);
      if (valor==9)
         {
            valor=0;
         }
      valor=valor+1;
   }
else if (!input(PIN_B5))
   {
      delay_ms(50);
      if (valor==0)
         {
            valor=9;
         }
      valor=valor-1;
   }
else if (!input(PIN_B6))
   {
      delay_ms(50);
      cuenta=cuenta+1;
      if (cuenta==1)
         {
            u=valor;
         }
      else if (cuenta==2)
         {
            d=valor;
         }
      else if (cuenta==3)
         {
            c=valor;
         }
      else if (cuenta==4)
         {
            m=valor;
         }
      else
      cuenta=0;
   }
else
flash_led_up();
}
}


Si pudieran ayudarme se los agradecería bastante.

Desconectado pocher

  • Moderador Local
  • DsPIC30
  • *****
  • Mensajes: 2568
RE: señal con frecuencia variable
« Respuesta #1 en: 09 de Septiembre de 2004, 06:16:00 »
A ver si te hecho una mano.

De entrada los pulsadores deben de ir por interrupción, de lo contrario los contadores van a ir locos. Vete corrigiendo y seguimos.

Desconectado badtzdizzy

  • Colaborador
  • PIC16
  • *****
  • Mensajes: 234
RE: señal con frecuencia variable
« Respuesta #2 en: 09 de Septiembre de 2004, 18:38:00 »
Hola Pocher

Pues muchas gracias por la ayuda que pudieras darme, ahorita tengo otro problema que necesito resolver lo más pronto posible. No se que estoy haciendo mal a la hora de querer generar una señal cuadrada de frecuencia constante y ciclo de trabajo del 50%. Estoy utilizando for"s pero al momento de encender el pic pues solo me manda un nivel bajo si dejo fuera de los for los output y un nivel alto si dejo los output dentro de uno de los for.
Codigo:

#include <16f874A.h>
#fuses HS, NOPROTECT, NOWDT, NOPUT, NOBROWNOUT, NOLVP, NOCPD, WRT  //define los fusibles que se deben poner en al parte al momento de programar
#use delay(clock=20000000)  //le dice al compilador la velocidad del procesador y habilita el uso de las funciones delay_ms() and delay_us().

void main()
{
   int i,j;
   int periodo=1;
   int ciclo=10;
   
   set_tris_a(0x00);
   set_tris_b(0xFF);
   
   while(TRUE)
      {
   
         for(i=1;i=periodo;i++)
            {
               for(j=1;j=ciclo;j++)
                  {
                     //output_high(PIN_A0);
                     delay_ms(1);
                  }
            }
         output_high(PIN_A0);
                  for(i=1;i=periodo;i++)
            {
               for(j=ciclo;j<20;j++)
                  {
                     //output_low(PIN_A0);
                     delay_ms(1);
                  }
            }
         output_low(PIN_A0);
               }
}




Ahora si que no se ni por donde. De antemano gracias por la ayuda

Desconectado pocher

  • Moderador Local
  • DsPIC30
  • *****
  • Mensajes: 2568
RE: señal con frecuencia variable
« Respuesta #3 en: 10 de Septiembre de 2004, 01:15:00 »
Aquí lo tienes:

Codigo:
#include <16f874A.h>
#fuses HS, NOPROTECT, NOWDT, NOPUT, NOBROWNOUT, NOLVP, NOCPD, NOWRT  //define los fusibles que se deben poner en al parte al momento de programar
#use delay(clock=20000000)  //le dice al compilador la velocidad del procesador y habilita el uso de las funciones delay_ms() and delay_us().

void main()
{
   int i,j;
   int periodo=1;
   int ciclo=10;
   
   set_tris_a(0x00);
   set_tris_b(0xFF);
   
   while(TRUE)
      {
   
         //for(i=1;i=periodo;i++)
         for(i=1;i<=periodo;i++)
            {
               for(j=1;j<=ciclo;j++)
                  {
                     //output_high(PIN_A0);
                     delay_ms(1);
                  }
            }
         output_high(PIN_A0);
                  for(i=1;i<=periodo;i++)
            {
               for(j=ciclo;j<20;j++)
                                 {
                     //output_low(PIN_A0);
                     delay_ms(1);
                  }
            }
         output_low(PIN_A0);
               }
}



El error estaba en que te faltaba el signo < y en los FUSES es NOWRT

¿Porqué no lo haces con PWM? Es más elegante y rápido.

Un saludo

PD. Cuando quieras seguimos con el otro.


Desconectado badtzdizzy

  • Colaborador
  • PIC16
  • *****
  • Mensajes: 234
RE: señal con frecuencia variable
« Respuesta #4 en: 10 de Septiembre de 2004, 16:43:00 »
Pues muchas gracias Pocher, ahora se que estaba haciendo mal. Sabes, el chiste del programa que quiero hacer es que necesito generar una señal cuadrada con un rango de frecuencias entre 20 y 3000 pulsaciones por minuto, lo que equivaldria a 0.3333 y 50 Hz. El programa que hice para hacerlo es el siguiente:
Codigo:

#include <16f874A.h>
#fuses HS, NOPROTECT, NOWDT, NOPUT, NOBROWNOUT, NOLVP, NOCPD, NOWRT  
#use delay(clock=20000000)  
#include<lcd.c>

int i,j;
int periodo=1;
int ciclo=10;
int duty;
int freq;


void flash_led_up()
{
   for(i=1;i<=periodo;i++)
      {
         for(j=1;j<=ciclo;j++)
            {
               output_high(PIN_A0);
               delay_ms(1);
            }
      }
   
   for(i=1;i<=periodo;i++)
      {
         for(j=ciclo;j<20;j++)
            {
               output_low(PIN_A0);
               delay_ms(1);
            }
      }
     
      lcd_putc("f");
      lcd_gotoxy(1,1);
      freq=50/periodo;
      printf (lcd_putc, "Freq=%2d Hz", freq);
      lcd_gotoxy(9,2);
      lcd_putc(37);
      lcd_gotoxy(1,2);
      duty=5*ciclo;
      printf (lcd_putc, "Duty=%2d", duty);
}

void main()  
{
   set_tris_a(0x00);
   set_tris_b(0xFF);
   port_b_pullups(TRUE);
   lcd_init();


while (TRUE)
{
while (input(PIN_B4)&&input(PIN_B5)&&input(PIN_B6)&&input(PIN_B7))
   {
      flash_led_up();
   }

   if (!input(PIN_B4))
      {
         delay_ms(30);
         if (periodo==1)
         periodo=50;
         else
         periodo=periodo-1;   
         
         while(!input(PIN_B4))
            {
               //Espera a que se libere el botón
            }
         delay_ms(30);
      }   
   else if (!input(PIN_B5))
      {
         delay_ms(30);
         if(periodo==50)
         periodo=1;
         else
         periodo=periodo+1;
      
         while(!input(PIN_B5))
            {
               //Espera a que se libere el botón
            }
         delay_ms(30);
      }
   else if (!input(PIN_B6))
      {
         delay_ms(30);
         if(ciclo==19)
         ciclo=1;
         else
         ciclo=ciclo+1;
         while(!input(PIN_B6))
            {
               //Espera a que se libere el botón
            }
         delay_ms(30);
      }
   else if (!input(PIN_B7))
      {
         delay_ms(30);
         if(ciclo==1)
         ciclo=19;
         else
         ciclo=ciclo-1;
         while(!input(PIN_B7))
            {
               //Espera a que se libere el botón
            }
         delay_ms(30);
      }   
   else
   flash_led_up();
}
}


En general hace lo que le pido, solo que tengo ciertos problemillas. Uno es que para periodos grandes por ejemplo mayores a 1s, los botones como que no responden. Y ahora el más reciente problema es que al usar el lcd, las instrucciones me generan un retardo extra y cuanto debería de tener un ciclo de trabajo del 50% pues ya no lo tengo.
Bueno, como me habías dicho, empezaré a trabajar con las interrupciones para los botones y te diré como voy. De antemano gracias por la ayuda.

PD: perdón por postear 2 veces el mismo problema.

Desconectado badtzdizzy

  • Colaborador
  • PIC16
  • *****
  • Mensajes: 234
RE: señal con frecuencia variable
« Respuesta #5 en: 10 de Septiembre de 2004, 17:44:00 »
Listo !!!

Lo del retardo extra ya lo arreglé, solo era cuestión de no estar llamando a imprimir siempre. Ahora empezaré a trabajar las interrupciones para ver si eso me ayuda a la hora de trabajar con periodos grandes.
Muchas Gracias Pocher.

Desconectado pocher

  • Moderador Local
  • DsPIC30
  • *****
  • Mensajes: 2568
RE: señal con frecuencia variable
« Respuesta #6 en: 10 de Septiembre de 2004, 23:58:00 »
Respecto a que tienes problemas al trabajar con periodos grandes, supongo que te referirás a meter números grandes en el delay_ms(variable).

Te comento una cosilla:

- Si en delay_ms metes dentro una constante, por ejemplo delay_ms(356), el rango máximo es hasta 65535, es decir 65,5s.

- Sin embargo si en delay_ms metes dentro una variable el rango máximo que puede tomar esta, es solo hasta 255.

Esta restricción me llevó de cabeza en su momento, hasta que miré el manual.

Prueba a hacer las temporizaciones usando algún TIMER, ya que si usas delay_ms vas a tener problemas con las temporizaciones pequeñas (por ejemplo 1ms) al desdoblarse las instrucciones C a ensamblador.

Por supuesto los pulsadores y representación en LCD por interrupción por cambio de estado.

Un saludo

Desconectado badtzdizzy

  • Colaborador
  • PIC16
  • *****
  • Mensajes: 234
RE: señal con frecuencia variable
« Respuesta #7 en: 12 de Septiembre de 2004, 23:42:00 »
Gracias por los tip"s

Sabes, este fin de semana me puse a pensar en cual es el problema que tengo y creo saber que no hay nada mal simple y sencillamente como estoy haciendo un programa por procesos sin interrupciones pues cuando genero señales del orden de segundos pues el boton parece no responder pero lo que està sucediendo es que como el periodo es grande pues no presiono el botón en el momento que se hace la pregunta, y me di cuenta porque en ocasiones si dejo oprimido el botòn, entonces si se realiza la rutina. Por eso tengo que hacerlo por interrupciones para que en cualquier momento se ejecute lo que necesito. Empezaré a hacerlo y te voy diciendo como voy para que me califiques. Muchas gracias Pocher.

Desconectado badtzdizzy

  • Colaborador
  • PIC16
  • *****
  • Mensajes: 234
RE: señal con frecuencia variable
« Respuesta #8 en: 13 de Septiembre de 2004, 19:16:00 »
Hola de nuevo Pocher

Pues empecé a hacer mi programa pero solo con interrupcion para los botones y pues como que no me gustó, porque se tarda en ejecutarse la función, y sin las interrupciones lo hace más rápido.
En fin, el programa con la interrupción por cambio de estado es este:
Codigo:

#include <16f874A.h>
#fuses HS, NOPROTECT, NOWDT, NOPUT, NOBROWNOUT, NOLVP, NOCPD, NOWRT
#use delay(clock=20000000)
#BIT RBIF=0xB.0
#byte PORTB=0x06
#include <lcd.c>

int i,j;
int periodo=1;
int ciclo=10;
int duty;
int freq;
int tecla=0;      //Bandera de tecla


void flash_led_up()
{
   for(i=1;i<=periodo;i++)
      {
         for(j=1;j<=ciclo;j++)
            {
               output_high(PIN_A0);
               delay_ms(1);
            }
      }
   
   for(i=1;i<=periodo;i++)
      {
         for(j=ciclo;j<20;j++)
            {
               output_low(PIN_A0);
               delay_ms(1);
            }
      }
}

void despliegue_lcd()
   {
      freq=50/periodo;
      duty=5*ciclo;
      lcd_gotoxy(1,1);
      printf (lcd_putc, "Freq=%2d Hz", freq);
      lcd_gotoxy(1,2);
      printf (lcd_putc, "Duty=%2d", duty);
   }

void signal()
   {
         if (tecla==1)
      {
         if (periodo==1)
         periodo=50;
         else
         periodo=periodo-1;   
      }   
   else if (tecla==2)
      {
         if(periodo==50)
         periodo=1;
         else
         periodo=periodo+1;
      }
   else if (tecla==3)
      {
         if(ciclo==19)
         ciclo=1;
         else
         ciclo=ciclo+1;
      }
   else if (tecla==4)
      {
         if(ciclo==1)
         ciclo=19;
         else
         ciclo=ciclo-1;
      }      
   else
   flash_led_up();
   }

#int_RB
void interrupcion()
    {
       
      int current;
      static int last=0xF0;      
      //Cuando la deteccion es de alto a bajo, last debe iniciar en 0xFF
      //para que detecte por primera vez de forma correcta que se presiona el
      //boton. En la libreria si se trabaja en el modo  bajo a alto, debe de
      //estar seguro que los botones se encuantran normalmente en cero.

      current=PORTB;      //Valor actual del puerto B
   
      if (!(bit_test(current,4))&&(bit_test(last,4))) {tecla=1;}   //Si el PIN_B4 pasa de 1 a 0 activa la tecla #1
      if (!(bit_test(current,5))&&(bit_test(last,5))) {tecla=2;}   //Si el PIN_B5 pasa de 1 a 0 activa la tecla #2
      if (!(bit_test(current,6))&&(bit_test(last,6)))   {tecla=3;}   //Si el PIN_B6 pasa de 1 a 0 activa la tecla #3
      if (!(bit_test(current,7))&&(bit_test(last,7)))   {tecla=4;}   //Si el PIN_B7 pasa de 1 a 0 activa la tecla #4

   delay_ms(50);   
   last=current;      //El valor actual se almace en last para el siguiente ciclo
}   //Al parecer se rectifica que efectivamente se oprime la tecla y que permanece oprimida por lo memos 50ms


void iniciar()
    {
     set_tris_b(0xFF);
     set_tris_a(0x00);
     port_b_pullups(TRUE);
     lcd_init();
     lcd_putc("f");
     lcd_gotoxy(9,2);
     lcd_putc(37);
     RBIF=0;
     enable_interrupts(int_RB);
     enable_interrupts(global);
    }
   
main()
   {
      iniciar();
         while(TRUE)
            {
               despliegue_lcd();
               flash_led_up();
               signal();
               tecla=0;
            }
   }


Ahora bien, cómo le podría hacer para establecer una base de tiempo con interrupciones en lugar de delay"s. Se como hacer la interrupción pero lo que no se es como habilitarla cuando yo quiera y tomarla como si fuera un delay, no se si me explique.
Muchas gracias por toda la ayuda.

Desconectado pocher

  • Moderador Local
  • DsPIC30
  • *****
  • Mensajes: 2568
RE: señal con frecuencia variable
« Respuesta #9 en: 14 de Septiembre de 2004, 02:42:00 »
A ver, varias cosas.

- La interrupción RB no te quita tiempo a la temporización de la onda. Debes poner el retardo antirebotes de 50 ms nada más entrar en la interrupción (no al salir).

- Lo que sí te quita tiempo son todas las funciones que has puesto en el while. Debieras haber dejado solo la función que hacer bascular la salida. Todas las demás metidas en la interrupción RB.

- Los bucles FOR utilizados con el delay_ms(1) van también a producir retrasos (habría que comprobar como cuanto son los retrasos dependiendo de los valores de las variables que usas en estos).

- Por último puedes hacer que sea el TIMER1 (por ejemplo) quien genere las temporizaciones de los estados alto y bajo. Así:

#INT_TIMER1

inttimer1()
{
      x++;
      set_timer1(64536);      //1ms
}

y en el while:

while(1)
{
     if (x=temp_ms)
     {
           output_bit(pin_a0,!input(pin_a0)),
           x=0;
     }

Aquí también habrían problemas con los tiempos por el if, habría que comprobar como cuanto se va. ¿Cual es el intervalo de frecuencias que necesitas?


Desconectado badtzdizzy

  • Colaborador
  • PIC16
  • *****
  • Mensajes: 234
RE: señal con frecuencia variable
« Respuesta #10 en: 16 de Septiembre de 2004, 15:50:00 »
Hola

Pues el rango de frecuencias a manejar va de las 20 pulsaciones por minuto a 6000 pulsaciones por minuto, o bien de 3000 ms a 20 ms. Voy a empezar a hacer las correcciones que me dices y te sigo contando como voy. Muchas gracias por la ayuda.

Desconectado pocher

  • Moderador Local
  • DsPIC30
  • *****
  • Mensajes: 2568
RE: señal con frecuencia variable
« Respuesta #11 en: 17 de Septiembre de 2004, 02:20:00 »
Los 20ms ¿no debieran de ser 10ms? Periodos: 10ms <---> 3s

El rango de las temporizaciones de los estados alto-bajo (semiperiodo) estará comprendido entre 5ms y 1,5s    ¿Es así?  Es importante tener esto claro.

Desconectado badtzdizzy

  • Colaborador
  • PIC16
  • *****
  • Mensajes: 234
RE: señal con frecuencia variable
« Respuesta #12 en: 20 de Septiembre de 2004, 16:36:00 »
Si es correcto, va de 20  ms a 3 seg, con el semiperiodo de 10 ms a 1.5 seg.

Ahora voy a hacer las correcciones que me dices y te cuento como me fue.

Gracias por toda la ayuda.

Desconectado badtzdizzy

  • Colaborador
  • PIC16
  • *****
  • Mensajes: 234
RE: señal con frecuencia variable
« Respuesta #13 en: 20 de Septiembre de 2004, 19:10:00 »
Hola Pocher

Pues ya quedó como yo quería y gracias a los consejos que me diste, en verdad te agradezco. Este es el código final:
Codigo:

#include <16f874A.h>
#fuses HS, NOPROTECT, NOWDT, NOPUT, NOBROWNOUT, NOLVP, NOCPD, NOWRT
#use delay(clock=20000000)
#BIT RBIF=0xB.0
#byte PORTB=0x06
#include <lcd.c>

int i,j;
long periodo=150;
int ciclo=10;
int duty;
long per;
int tecla=0;      //Bandera de tecla

void despliegue_lcd()
   {
      per=20*periodo;
      duty=5*ciclo;
      lcd_gotoxy(1,1);
      printf (lcd_putc, "Peri=%4ld", per);
      lcd_gotoxy(1,2);
      printf (lcd_putc, "Duty=%2d", duty);
   }


void flash_led_up()
{
   output_high(PIN_A0);
     for(i=1;i<=periodo;i++)
      {
         for(j=1;j<=ciclo;j++)
            {
               delay_ms(1);
            }
      }
   output_low(PIN_A0);
   for(i=1;i<=periodo;i++)
      {
         for(j=ciclo;j<20;j++)
            {
               delay_ms(1);      
            }
      }
}



void signal()
   {
   if (tecla==1)
      {
         tecla=0;
         if (periodo==1)
         periodo=150;
         else
         periodo=periodo-1;   
      }   
   else if (tecla==2)
      {
         tecla=0;
         if(periodo==150)
         periodo=1;
         else
         periodo=periodo+1;
      }
   else if (tecla==3)
      {
         tecla=0;
         if(ciclo==19)
         ciclo=1;
         else
         ciclo=ciclo+1;
      }
   else if (tecla==4)
      {
         tecla=0;
         if(ciclo==1)
         ciclo=19;
         else
         ciclo=ciclo-1;
      }      
   }

#int_RB
void interrupcion()
    {
       
      int current;
      static int last=0xF0;      
      //Cuando la deteccion es de alto a bajo, last debe iniciar en 0xFF
      //para que detecte por primera vez de forma correcta que se presiona el
      //boton. En la libreria si se trabaja en el modo  bajo a alto, debe de
      //estar seguro que los botones se encuantran normalmente en cero.
     
      delay_ms(50);
      current=PORTB;      //Valor actual del puerto B
      
   
      if (!(bit_test(current,4))&&(bit_test(last,4))) {tecla=1;}   //Si el PIN_B4 pasa de 1 a 0 activa la tecla #1
      if (!(bit_test(current,5))&&(bit_test(last,5))) {tecla=2;}   //Si el PIN_B5 pasa de 1 a 0 activa la tecla #2
      if (!(bit_test(current,6))&&(bit_test(last,6)))   {tecla=3;}   //Si el PIN_B6 pasa de 1 a 0 activa la tecla #3
      if (!(bit_test(current,7))&&(bit_test(last,7)))   {tecla=4;}   //Si el PIN_B7 pasa de 1 a 0 activa la tecla #4

   last=current;      //El valor actual se almace en last para el siguiente ciclo
   //Al parecer se rectifica que efectivamente se oprime la tecla y que permanece oprimida por lo memos 50ms
   signal();
   despliegue_lcd();
   }

void iniciar()
    {
     set_tris_b(0xFF);
     set_tris_a(0x00);
     port_b_pullups(TRUE);
     lcd_init();
     lcd_putc("f");
     lcd_gotoxy(11,1);
     printf (lcd_putc,"mseg";
     lcd_gotoxy(9,2);
     lcd_putc(37);
     RBIF=0;
     enable_interrupts(int_RB);
     enable_interrupts(global);
    }
   
main()
   {
      iniciar();
      despliegue_lcd();
         while(TRUE)
            {
               flash_led_up();
            }
   }


Por aquí voy a andar porque todavía tengo que hacer un programa para controlar un motor, entonces necesitaré de tu ayuda. Gracias.


 

anything