Alternativa al Delay

Hola

Resulta que estoy haciendo una alarma pero usando el delay(); donde un rele se queda activado durante 30 segundos, pero en ese momento que se apague y prenda un led. Y lo estoy haciendo con rtos, entonces por el delay las demás tareas se pausan.

Este es un código simple usando delay:

Código:
#include <16f628A.H>
#fuses xt, put, NOWDT, INTRC_IO, NOPUT, NOPROTECT, NOBROWNOUT, NOMCLR, NOLVP, NOCPD

#use delay(clock=4000000)

#use standard_io(b)
#use standard_io(a)
#BYTE port_a= 0x05
#BYTE port_b= 0x07


void Tarea();

void main(){
   
   set_tris_B(0x00);
   set_tris_a(0xFF);
  

   output_b(0x00);
   disable_interrupts(GLOBAL);
   do{
   
   Tarea();
   
   }while(1);
}



void Tarea()
{
   if (input(pin_a0)==1){
   output_high(PIN_b1);
   delay_ms(3000);
   
   output_low(PIN_b1);
   delay_ms(3000);
   
   output_high(PIN_b1);
   delay_ms(3000);
   
   output_low(PIN_b1);
   delay_ms(3000);
   }
}

¿Cual sería la alternativa para no usar delay, sin perjudicar a otros procesos? :confused:
 
...Puedes usar el rtos_yield();... y seria mejor que subas el codigo que tienes con el RTOS ya que asi como esta solo se puede sugerir ideas generales por ejemplo: Tambien puedes usas las interrupciones de los temporizadores que no se están usando.
 
Pues yo no uso delay ni RTOS por la simple razón que aprendí como administrar el tiempo.

Hay 2 maneras de hacer la multitarea.
1.- con un DELAY :LOL: si es posible
2.-timer que es la mejor opción si sabes configurar el timer.

Bueno, la idea es la siguiente:

Digamos que queremos prender un LED rojo 2 segundos y un segundo un led verde cada medio segundo, mientras que prendo un relevador por 3 segundos.
Todo al mismo tiempo.

La sintaxis es así para un timer:

Código:
void timer()
{
retardo++;
}

void main()
{

condiguarar timer

while(1)
{
codigo
}
}
El timer sólo incrementará una variable a un tiempo conocido, digamos 50us y lo único que hará el timer será incrementar cada 50us y nada mas.

La sintaxis es así para un delay:

Es parecida a la anterior pero si no sabemos configurar el timer y nos urge sacar el proyecto, es así:

Código:
void main
{
while(1)
{
código..

delay_us(50);
retardo++;
}
}
Ahora, así sería el ejemplo que mencioné con un DELAY a 50us

Código:
while(true)
{

//------CONTADOR ES 50us X 20 SON 1mS 

if(contador>=20)
{
   contador=0;
   milis++;
   aux1++; //esta variable es para mi propósito
  
   
   //----------1 SEGUNDO TIENE 1000 mS
   if(milis>=1000)
   {
      milis=0; //regreso milis a 0
      seg++;  //incremento la variable segundos
      seg2++;  //incremento la variable segundos 2
   }
}




//-------PRENDO  LED ROJO CADA 2SEG en A5----------

if(seg>=2)
{
  seg=0;
}

if(seg<=2)
{
   output_high(pin_A5);
}
else
      {
         output_low(pin_A5);
      }






// ------PRENDO UN LED VERDE CADA 500ms EN A6--------------

if(aux1>=500)
{
   aux1=0;
}

if(aux1<=500)
{
   output_high(pin_A6);
}
else
      {
         output_low(pin_A6);
      }

      

// ------PRENDO UN RELE CADA 3 s EN B1--------------

if(seg2>=3)
{
   seg2=0;
}

if(seg2<=3)
{
   output_high(pin_B1);
}
else
      {
         output_low(pin_B1);
      }
      
 
delay_us(50);
contador++;



}
 
Última edición por un moderador:
Pregunta: ¿Cómo usáis la instrucción SLEEP desde C? Junto con un timer, puede ser otra forma de hacer esperar el micro sin hacer nada, pero ahorrando energía.
 
...Des afortunadamente en la gama 16 de PIC al usar la instruccion SLEEP se detiene el reloj principal del sistema y por tanto el timer0 deja de funcionar, podría usarse el timer1 pero este tendría que estar funcionando con reloj externo.
 
Última edición:
En efecto, las únicas formas (al menos en el 16F877A que he estado leyendo), son el Timer1 en modo contador asíncrono, y el Watchdog Timer (funcionando ya dentro del modo SLEEP). Esto, para las interrupciones basadas en temporizadores, porque hay una decena de interrupciones externas que despertarán al micro, pero claro, no basadas en tiempo (salvo que se ponga un disparador externo).

¿Alguien sabe cómo programar esto desde C?
 
hola... Un nodo de salir del SLEEP en PIC16 es usando el desborde del perro guardián pero el tiempo a de ser múltiplo de base 2 de 18ms (este tiempo puede variar según la hoja de datos).
Este un ejemplo en CCS PicC.
Código:
#include <16F877A.h>

#FUSES WDT                      //Watch Dog Timer
#FUSES PUT                      //Power Up Timer
#FUSES BROWNOUT                 //Reset when brownout detected
#FUSES NOLVP                    //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#FUSES NOCPD                    //No EE protection
#FUSES NOWRT                    //Program memory not write protected
#FUSES NOPROTECT                //Code not protected from reading

#use delay(crystal=4000000,restart_wdt)
void main()
{
   setup_wdt(WDT_1152MS);      //perro guardián disparado cada 1.152s
   while(TRUE)
   {
      output_toggle(pin_b0);
      sleep();
   }
}
y este el mismo ejemplo en MikroC.
Código:
void main()
{
   portb.rb0=0;
   trisb.b0=0;
   option_reg=option_reg&0b11111110;   //prescalador asignado al perro guardián
                                       //prescalador=64 -> 64*18ms=1.152s
   while(1)
   {
      portb.rb0=!portb.rb0;
      asm{sleep}
   }
}
Ambos códigos producen el mismo resultado.
Dibujo.PNG


Con el timer1 también es posible salir del SLEEP pero este tiene que estar configurado con una fuente de reloj externa y si se desea usar un cristal como oscilador hay que activar el oscilador del timer1 mediante T1OSCEN (des afortunadamente proteus no simula el oscilador del timer1).

Este un ejemplo con CCS PicC.
Código:
#include <16F877A.h>

#FUSES NOWDT                    //No Watch Dog Timer
#FUSES PUT                      //Power Up Timer
#FUSES BROWNOUT                 //Reset when brownout detected
#FUSES NOLVP                    //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#FUSES NOCPD                    //No EE protection
#FUSES NOWRT                    //Program memory not write protected
#FUSES NOPROTECT                //Code not protected from reading

#use delay(crystal=4000000)



#int_timer1
void interrupcion_timer1()
{
   #byte tmr1h=GETENV("SFR:TMR1H")
   tmr1h=0x80;
}
void main()
{
   #bit t1oscen=GETENV("BIT:T1OSCEN")
   set_timer1(0x8000);
   setup_timer_1(T1_EXTERNAL|T1_DIV_BY_1);
   t1oscen=1;                                   //oscilador del timer1 activado
   enable_interrupts(int_timer1);
   enable_interrupts(global);
   while(TRUE)
   {
      output_toggle(pin_b0);
      sleep();
   }
}
Este el mismo ejemplo en MikroC.
Código:
void interrupciones() iv 0x0004 ics ICS_AUTO
{
   tmr1h=0x80;
   pir1.tmr1if=0;
}
void main()
{
   portb.b0=0;
   trisb.b0=0;
   tmr1h=0x80;
   tmr1l=0x00;
   t1con=0b00001111;   //prescalador=1
                       //oscilador del timer1 activado
                       //modo asíncrono
                       //fuente de reloj externo
                       //timer1 activado
   pie1.tmr1ie=1;      //interrupción del timer1 activado
   intcon=11000000;    //habilitador de interrupciones global activado
                       //habilitador de interrupciones de periféricos activado
   while(1)
   {
      portb.b0=!portb.b0;
      asm{sleep}
   }
}
Ambos códigos producen el mismo resultado.
Dibujo1.PNG
 

Adjuntos

  • wdt.rar
    119 KB · Visitas: 3
  • tmr1.rar
    125.6 KB · Visitas: 4
Hola, perdon por reavivar el post pero justo estoy buscando otra alternativa al Delay en este caso dentro en las interrupciones, como ustedes sabran no es conveniente colocar delays dentro de las interrupciones, y en la simulacion del CCS te tira un WARNING, entonces que alternativa se podria usar para realizar un antirrebote en un pulsador que llama a una interrupcion si el delay no es conveniente ? existe otra forma de hacer un antirrebote sin delays ? gracias !
 
si la hay el antirrebote se hace de los siguientes marranos modos

este es el caso de hacer porquerias:

meter un delay una vez pulsado el boton

Código:
if(pulsado==1)
{
delay_ms(1000);
//codigo
}

otro es:

Código:
if(pulsado==1)
{

//codigo
while(condicion)
{
}
}

ambos metodos atoran el micro pero hay un modo donde se usa el timer para decrementar una variable
asi el micro en teoria cuando cumpla el cometido dejara de rebotar pero no es perfecto

el codigo es el siguiente:

Código:
unsigned char decremento1;
unsigned char decremento2;


void timer()
{
   decremento1--;                //decremento para el antirrebote del boton 1
   decremento2--;                //decremento para el antirrebote del boton 2

//cargar otravez el timer
}

if(!input(pin_B4))        //checamos si se pulso la tecla y si ha sido soltada
      {
         if(decremento1<=1)                  //si el decremento llega a 0 hacemos lo que tenemos que hacer
         {
            //output_high(PIN_A4);
            cuenta++;
         }
      }
      else{ 
            decremento1=50;                 //si no cargamos el decremento a 100 para que no decremente
            //output_low(PIN_A4);
          }

como se ve en el codigo se acabaria el rebote pero en la practica si hay algo de fallas para eso se debe hacer un candado que bloque el boton hasta que lo soltemos y eso se haria con una variable que ayude a bloquear la pregunta if


Código:
unsigned char decremento1;
unsigned char decremento2;


void timer()
{
   decremento1--;                //decremento para el antirrebote del boton 1
   decremento2--;                //decremento para el antirrebote del boton 2

//cargar otravez el timer
}



void soltar()
{
if (input(pin_B4))
   boton1=0;

if (input(pin_B5))
   boton2=0;
}


//esto va dentro del while(true)

      soltar();   //funcion de limpiar boton



      if((!input(pin_B4))&&(!boton1))        //checamos si se pulso la tecla y si ha sido soltada
      {
         if(decremento1<=1)                  //si el decremento llega a 0 hacemos lo que tenemos que hacer
         {
            boton1 = 1;                      //indicamos que se ha predionado la tecla
            //output_high(PIN_A4);
            cuenta++;
         }
      }
      else{ 
            decremento1=50;                 //si no cargamos el decremento a 100 para que no decremente
            //output_low(PIN_A4);
          }               




      if((!input(pin_B5))&&(!boton2))        //checamos si se pulso la tecla y si ha sido soltada
      {
         if(decremento2<=1)                  //si el decremento llega a 0 hacemos lo que tenemos que hacer
         {
            boton2 = 1;                      //indicamos que se ha predionado la tecla
            //output_high(PIN_A5);
            cuenta--;
         }
      }
      else{ 
            decremento2=50;                 //si no cargamos el decremento a 100 para que no decremente
            //output_low(PIN_A5);
          }
 
muchas gracias por las respuestas, la libreria de Darkbites es genial, hace casi lo mismo que menciona TRILOBYTE pero resumido en una sola funcion! mi duda es como variar el Delay en la funcion de Darkbites: button(pin_a0,0,255,10,B0,1)
se hace variando el parametro 3=255 o el parametro 4=10 . Podrias darme algun ejemplo ? como ser si quiero un delay de 20ms como hacerlo ? muchas gracias de nuevo, saludos !
 
mi problema es el ingles, por eso no entendi bien cual de los 2 parametros tengo que modificar, bueno voy a ir tocando un poco y simulando a ver que sale :D
 
Atrás
Arriba