Autor Tema: Retardos sin usar delay_ms()  (Leído 5438 veces)

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

Desconectado jeremylf

  • Colaborador
  • PIC24H
  • *****
  • Mensajes: 1341
Retardos sin usar delay_ms()
« en: 31 de Marzo de 2007, 13:35:55 »
Hola a todos. La duda q tengo es como puedo hacer retardos sin usar los delay_ms() yaq si uso esto me detiene todo el proceso del PIC, y bueno no quiero q pase esto.

Haber yo hice algunas pruebas asignando y sumando variables poniendo una condicion pero no me va, aqui les dejo el codigo para q me digan q falla tiene y como puedo implementar estos retardos.

Código: [Seleccionar]
#include <18f452.h>
#fuses XT,NOWDT,NOPROTECT,PUT
#use delay(clock=4000000)
#use fast_io(b)
#int_rtcc
void handle_rtcc_int()
   {
   //Output_toggle: Cambiar al estado contrario al q esta (1 o 0).
   Output_Toggle(PIN_C2);
   Set_timer0(1000);
   }

void main(void)
   {
   unsigned int tiempo=100;
   unsigned int activado=0;
   unsigned int codigo=0;
   long i=0;

   set_tris_b(0b00000001);
   disable_interrupts(GLOBAL);
   output_b(0);

   while(1)
      {
      if (input(PIN_B0)==0)
         {
         activado=1;
         setup_timer_0(RTCC_DIV_16 | RTCC_8_BIT);
         enable_interrupts(int_rtcc);
         enable_interrupts(global);
         }

      //Si la puerta esa abierta o cerrada.
      if (activado==0)
         {
         i++;
         if (i>=2000)
            {
            output_high(PIN_B1);
            }

         }
      else
         {
         if (input(PIN_A4)==0)
            {
             disable_interrupts(int_rtcc);
             disable_interrupts(GLOBAL);
             activado=0;
            }
         output_high(PIN_B1);
         delay_ms(100);
         output_low(PIN_B1);
         delay_ms(100);
        }
      }
   }

salu2  8)

Desconectado Nocturno

  • Administrador
  • DsPIC33
  • *******
  • Mensajes: 18286
    • MicroPIC
Re: Retardos sin usar delay_ms()
« Respuesta #1 en: 31 de Marzo de 2007, 14:15:17 »
Lo ideal sería utilizar un timer. Si quieres ver un ejemplo, aunque está diseñado para dsPIC, puedes echar un vistazo aquí: Asistente para la generación automática de retardos

La sintaxis no te servirá para un PIC, pero la filosofía es la misma.

Desconectado maunix

  • Moderadores
  • DsPIC33
  • *****
  • Mensajes: 4751
    • Mi Sitio Web Personal
Re: Retardos sin usar delay_ms()
« Respuesta #2 en: 31 de Marzo de 2007, 14:22:56 »
Te sugiero lo mismo que Manolo, que uses un timer (además salvo que uses un módulo externo al pic no tienes otra alternativa). 

El timer si lo usas por interrupción, podrías hacer que interrumpa al micro cada 1 mseg y contar las veces que lo hace, de esa forma, manejas tus retardos en "milisegundos" sin que por ello el resto del software se detenga.

Luego al final del bucle de control de tus subrutinas, verificas el estado de la cuenta de "mseg" para luego seguir con lo que debas hacer.

En general, esto no debe ir solo sino de la mano de algún control por máquina de estados que te permita continuar con la siguiente tarea después del retardo.  Además esto es muy útil cuando debes llevar varias tareas en paralelo y cada tarea debe contemplar retardos diferentes para continuar su ejecución.

Saludos
- La soberbia de un Einstein es entendible.. la de un salame es intolerable (A.Dolina)
- En teoría no hay diferencia entre la teoría y la práctica. En la práctica... si la hay.
- Lee, Lee, Lee y luego pregunta.(maunix)
- Las que conducen y arrastran al mundo no son las máquinas, sino las ideas (V. Hugo)
- Todos los hombres se parecen por sus palabras; solamente las obras evidencian que no son iguales.(Moliere)
- Todo debería ser hecho tan simple como sea posible pero no mas simple que eso.(A.Einstein)

Desconectado Cryn

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 4169
Re: Retardos sin usar delay_ms()
« Respuesta #3 en: 01 de Abril de 2007, 01:11:47 »
y cual es el maximo valor en segundos (ya sea milis o micros) qeu se puede contar con algun timer sin tener un contador de interrupciones por timer? se entendio? y el mismo valor será en un timer 0, 1, 2 ó 3???
.

Desconectado Nocturno

  • Administrador
  • DsPIC33
  • *******
  • Mensajes: 18286
    • MicroPIC
Re: Retardos sin usar delay_ms()
« Respuesta #4 en: 01 de Abril de 2007, 02:02:51 »
Depende de muchas variables:
- el PIC que estés usando
- la frecuencia del oscilador
- el nº de bits del timer que estés usando

Concreta un poco más y se podrá calcular.

Desconectado RiBerZerO

  • PIC12
  • **
  • Mensajes: 52
Re: Retardos sin usar delay_ms()
« Respuesta #5 en: 01 de Abril de 2007, 02:17:50 »
El timer lo puedes configurar de varias maneras, todo esta en las hojas de especificaciones busca el timer1 que te servira, yo estoy haciendo un programa que utiliza algo parecido y utilizo el timer 1 por interrupcion

Código: C
  1. #include <18F4585.h>
  2. #device adc=8
  3.  
  4. #FUSES NOWDT                    //No Watch Dog Timer
  5. #FUSES WDT128                   //Watch Dog Timer uses 1:128 Postscale
  6. #FUSES INTRC_IO                 //Internal RC Osc, no CLKOUT
  7. #FUSES NOPROTECT                //Code not protected from reading
  8. #FUSES NOBROWNOUT               //No brownout reset
  9. #FUSES BORV21                   //Brownout reset at 2.1V
  10. #FUSES NOPUT                    //No Power Up Timer
  11. #FUSES NOCPD                    //No EE protection
  12. #FUSES STVREN                   //Stack full/underflow will cause reset
  13. #FUSES NODEBUG                  //No Debug mode for ICD
  14. #FUSES NOLVP                    //No Low Voltage Programming on B3(PIC16) or B5(PIC18)
  15. #FUSES NOWRT                    //Program memory not write protected
  16. #FUSES NOWRTD                   //Data EEPROM not write protected
  17. #FUSES IESO                     //Internal External Switch Over mode enabled
  18. #FUSES FCMEN                    //Fail-safe clock monitor enabled
  19. #FUSES NOPBADEN                 //PORTB pins are configured as DIGITAL input channels on RESET
  20. #FUSES BBSIZ4K                  //4K words Boot Block size
  21. #FUSES NOWRTC                   //configuration not registers write protected
  22. #FUSES NOWRTB                   //Boot block not write protected
  23. #FUSES NOEBTR                   //Memory not protected from table reads
  24. #FUSES NOEBTRB                  //Boot block not protected from table reads
  25. #FUSES NOCPB                    //No Boot Block code protection
  26. #FUSES LPT1OSC                  //Timer1 configured for low-power operation
  27. #FUSES MCLR                     //Master Clear pin enabled
  28. #FUSES NOXINST                  //Extended set extension and Indexed Addressing mode disabled (Legacy mode)
  29.  
  30. #use delay(clock=32000000)
  31.  
  32. #use FAST_IO(B)
  33. #use FAST_IO(C)
  34. #use FAST_IO(D)
  35.  
  36. #BYTE FILAS=0xF81
  37. #BYTE DATOS=0xF82
  38. #BYTE COLUM=0xF83
  39. #BYTE TRISB=0xf93
  40. #BYTE TRISC=0xf94
  41. #BYTE TRISD=0xf95
  42.  
  43.  
  44. BYTE ndesplegar[6]={0};
  45. BYTE Display[6][3]={0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF  0xFF 0xFF 0xFF 0xFF};
  46. BYTE col=0b00000100;
  47. BYTE fil=0b00010000;
  48. BYTE NoDis=0,NoMod=0;
  49.  
  50. #inline
  51. void NOP(){
  52.  #asm
  53.  Nop
  54.  #endasm
  55. }
  56.  
  57. #INT_TIMER1
  58. void Matriz( void ){
  59.    
  60.    DATOS=0;
  61.    if(col==0){
  62.       fil<<=1;
  63.       col=0x04;
  64.    }
  65.    if(fil==0x80)
  66.       fil=0x10;
  67.    if(NoDis==3){
  68.       NoMod++;
  69.       NoDis=0;
  70.    }
  71.    if(NoMod==6)
  72.       NoMod=0;
  73.    FILAS=fil;
  74.       COLUM=col;
  75.    DATOS=Display[NoMod][NoDis++];
  76.    col<<=1;
  77.    set_timer1(0xE119);
  78.    NOP();
  79.    return;
  80. }
  81.  
  82. void main(){
  83.    BYTE i,j;
  84.    setup_adc_ports(NO_ANALOGS);
  85.    setup_adc(ADC_OFF);
  86.    setup_oscillator(OSC_32MHZ|OSC_NORMAL|OSC_PLL_ON);
  87.    set_timer1(0xE0BF);
  88.    SETUP_TIMER_1((T1_INTERNAL|T1_DIV_BY_1)&0x7F);
  89.    ENABLE_INTERRUPTS(INT_TIMER1);
  90.    ENABLE_INTERRUPTS(GLOBAL);
  91.    TRISB=0x8F;
  92.    TRISC=0x00;
  93.    TRISD=0x03;
  94.    
  95.    while(TRUE);
  96. }

Disculpa que no lo haya podido reducir pero se ven las partes principales del programa por interrupcion

para configurar el timer tienes que decidir si vas a usar el reloj del sistema o uno externo, si utilizas el de sistema tienes que dividir la frecuencia entre cuatro

Fosc/4

Ahora lo siguiente a configurar es el preescaler el cual dependiendo del pic puedes usarlo a 2 ,4, 8, etc. Este es un divisor de frecuencia, de la frecuencia de sistema Fosc/4 con esto configuraras la frecuencia del timer.

El timer genera una interrupcion cuando pasa de FFFF a 0000 es una interrupcion de sobreflujo.

Asi entonces para generar un evento, lo que tienes que hacer es definir la frecuencia de tu timer, despues de acuerdo a eso, calcular cuantos pulsos de reloj se necesitan para ocupar el tiempo que tu quieres, con este dato del numero de ciclos, se los restas a FFFF ya que los timer siempre son incrementales. y disparas el reloj, cuando tenga un sobreflujo, activara la interrupcion y ejecutara el codigo de la funcion correspondiente.

Espero te ayude cualquier cosa avisa  :-/ :-/ :-/
No SUEÑES tu vida, VIVE tu sueño

Desconectado jeremylf

  • Colaborador
  • PIC24H
  • *****
  • Mensajes: 1341
Re: Retardos sin usar delay_ms()
« Respuesta #6 en: 07 de Abril de 2007, 17:19:36 »
Ola, q tal?
Decir q alfinal pude lograrlo haciendo pequeños retardos de 50 milisegundos para q no detuvieran todo el proceso del PIC, y sumando una variable despues de esto para asi confirmar el prendido y el apagado del led. Quiza haya alguna otra forma de hacerlo sin delay's pero esto me ha servido, Aqui les dejo el codigo:

Código: [Seleccionar]
#include <18f452.h>
#fuses XT,NOWDT,NOPROTECT,PUT
#use delay(clock=4000000)
#use fast_io(b)
#int_rtcc
void handle_rtcc_int()
   {
   //Output_toggle: Cambiar al estado contrario al q esta (1 o 0).
   Output_Toggle(PIN_C2);
   Set_timer0(1000);
   }

void main(void)
   {
   //unsigned int tiempo=100;
   //long i=0;
   unsigned int apretado=0;
   unsigned int activado=0;
   unsigned int codigo=0;
   unsigned int mom=27;
   
   set_tris_b(0b00000001);
   disable_interrupts(GLOBAL);
   output_b(0);

   while(1)
      {
      mom++;
      if (input(PIN_B0)==0)
         {
         if (activado==0)
            {
            activado=1;
            mom=1;
            }
         }

      //SI LA PUERTA ESTA ABIERTA O CERRADA.
      if (activado==0)
         {
         delay_ms(50);
         if (mom>=30)
            {
            output_high(PIN_B1);
            if (mom>=32)
               {
               output_low(PIN_B1);
               mom=0;
               }
            }
         }
      else
         {
         //ALARMA.
         setup_timer_0(RTCC_DIV_16 | RTCC_8_BIT);
         enable_interrupts(int_rtcc);
         enable_interrupts(global);
         if (mom>=2)
            {
            output_high(PIN_B1);
            if (mom>=4)
               {
               output_low(PIN_B1);
               mom=0;
               }
            }
         delay_ms(50);
         
         //CODIGO PARA DESACTIVAR.
         if (input(PIN_A4)==0)
            {
            if (apretado==0)
               {
               codigo++;
               apretado=1;
               }
            if (codigo==5)
               {
               disable_interrupts(int_rtcc);
               disable_interrupts(GLOBAL);
               activado=0;
               mom=0;
               apretado=0;
               codigo=0;
               output_low(PIN_b1);
               }
            }
         else
            {
            apretado=0;
            }
         }
      }
   }

Ojala a alguien le sirve.
Y gracias igualmente a los q respondieron. Mas q nada gracias por su tiempo  yaq las formas q me han dicho no les e aplicado/entendido muy bien:P De todas formas se agradece  :mrgreen:


salu2 8) 8)

Desconectado PalitroqueZ

  • Moderadores
  • DsPIC33
  • *****
  • Mensajes: 5474
    • Electrónica Didacta
Re: Retardos sin usar delay_ms()
« Respuesta #7 en: 01 de Abril de 2008, 12:50:46 »
Hola

también me enfrento a una situación similar, de inmediato les explico:

En el archivo lcd.c en la función lcd_init() hay una parte donde se necesita un retardo de 15ms, que en mi caso es una exageración porque necesito hacer otras cosas "simultaneas", entonces yo podría eliminar la línea

delay_ms(15) por unas cuantas lineas equivalente a cargar el timer (previamente configurado la base de tiempo) y con un return me salgo de lcd_init() y continuar con otros procesos.

la única forma de continuar con las siguientes lineas de lcd_init() es que esté sensando continuamente dentro de esa función y por la espera de unas banderas (que se activaran cuando termine de pasar los 15ms temporizados por el timer)

sería mas o menos así

void lcd_init()
if(!bRetardo15ms) then
... aqui van las primeras lineas de lcd_init

bRetardo15ms=1;
return
else
... aqui continua con las siguientes lineas después de esperar 15ms



el detalle que le veo a esto es que a diferencia del delay_ms(15) solamente ejecutaría lcd_init UNA SOLA VEZ dentro del programa principal, y con este método encerraria dicha función dentro de un bucle donde siempre estaría preguntando así se haya ejecutado la primera vez, por consiguiente se pierde mas tiempo y se van a segmentos de programas que no valen la pena ejecutar otra vez

¿alguna idea?

« Última modificación: 01 de Abril de 2008, 12:54:08 por PalitroqueZ »
La propiedad privada es la mayor garantía de libertad.
Friedrich August von Hayek

Desconectado RICHI777

  • Colaborador
  • PIC24H
  • *****
  • Mensajes: 1498
Re: Retardos sin usar delay_ms()
« Respuesta #8 en: 01 de Abril de 2008, 13:15:12 »
Hola, mi opinion, Un delay es eso, un retardo de tiempo, podes hacerlo x soft ( funciones que estan prediseñadas para que en base a la frecuencia de clock tarden de manera deterministica un tiempo X, o como muy bien sugirio Maunix, atravez de un timer, contando las interrupciones ( nomrmalmente se llama timertciks ) y despues de verificando el tiempo pasado. Normalmente este ulitmo metodo se utiliza mas para aplicar timeouts que para efectuar delays, ejemplo estoy esperando un evento externo por cierta cantidad de tiempo si el evento no se produce fallo por timeout.
Con respecto a lo que vos queres, me parece que deberias cambiar la filosofia del diseño, si necesitas que varias cosas se esten ejecutando en paralelo, bueno deberias pensar en algun RTOS.
Saludos !
« Última modificación: 01 de Abril de 2008, 14:20:07 por RICHI777 »

Desconectado psyke

  • PIC10
  • *
  • Mensajes: 3
Retardos sin usar delay_ms()
« Respuesta #9 en: 10 de Septiembre de 2016, 12:13:54 »
Hola, disculpen que reviva el tema, supuse que es mejor escribir acá y no crear uno nuevo (corrijanme si me equivoco  :oops: :oops:)
Lo que quería preguntar es cómo utilizar el timer0 (ya aprendí como funciona) para reemplazar el DELAY_MS(1); marcado en el código, ya que según leo por todos lados, no es bueno usar delay_ms.
El código es poco eficiente ya que es uno de mis primeros códigos un poco más complejos, es una matriz de LEDs de 8x80 que ya funciona por proteus. Omití gran parte del codigo ya que me pareció innecesario incluirlo, iba a complicar las cosas.
El código es para un PIC18F4550.

Además la idea es que la velocidad de desplazamiento de la frase en la matriz sea variable, por lo que quiero implementar el TIMER0 para que pueda variar el valor del retraso, ya que la velocidad depende de él.

Se me había ocurrido meter el código dentro de la interrupción por desborde del T0 pero sería una bestialidad... Así que les pido ayuda a ustedes. Gracias

Código: [Seleccionar]
   while(1)
   {
      for(cont=0;cont<80;cont++)
      {
         for(conta=0;conta<=cont;conta++)
         {
            conta=salvar;
            for(i=0;i<80;i++)
            {
               if(i==0)              //envia 1 a los reg
               {
                  enviar1;
                  long_actual++;
                  if((long_actual)>=longitud)
                  {
                     long_actual=0;
                     if((contaletra+2)>longfra)
                     {
                        contaletra = 0;
                     }
                     else
                     {
                        contaletra++; 
                     }
                     SeleccionaCaracter();
                  }
                  L[0] = C[conta2];
                  output_d(L[0]);
                  conta2++;
                  imprimio=1;
               }
               else                      //envia 0 a los reg
               {
                  enviar0;
               } 
               if(i<=conta && !(imprimio))
                  {
                        output_d(L[i]);
                  }
            delay_ms(1); ///////////////////////////////////////////ESTE DELAY
            output_d(0);
            imprimio=0;
            }
            RotacionColumnas();
         }
         salvar=conta;
      }
   }
}

Desconectado ALMNET

  • PIC10
  • *
  • Mensajes: 1
Re:Retardos sin usar delay_ms()
« Respuesta #10 en: 11 de Septiembre de 2016, 06:31:21 »
Saludos!

Tambien he tenido ese problema que por x motivo no puedo usar delay_ms.... Para eso caso tomo la solución de la competencia (arduino) y su funcion millis()... El procedimiento sería el siguiente:
1.- Configuro un temporizador cualquiera que no esté utilizando para que se interrumpa a 1mS lo mas exacto posible (usar los calculadores que se consiguen online, son muy precisos).
2.- Luego dentro de la interrupción incremento una variable tipo long o long long (millis) de 32 bits preferiblemente, En resumen esta variable se incrementará en 1 cada milisegundo.
3.- Antes de requerir la temporizacion, respaldar el valor de millis en otra variable tipo long long (Backup_millis).
4.- Si el retardo que requiero es por ejemplo de 10 seg, debe incrementarse la variable millis en 10 mil, para eso solo calculo la diferencia entre el estado actual y el estado anterior: Por ejemplo si backup_millis es igual a 3248, millis debe igual a 13248 para saber que ya se cumplieron los 10 segundos.

Para mayor info pueden buscar acerca de la funcion millis de arduino.
https://www.arduino.cc/en/Reference/Millis

De un tiempo para aca manejo las temporizaciones así y de verdad ha sido un alivio en muchos aspectos a la hora de manejar por ejemplo conversiones, comunicación serial, refrescamiento de pantalla lcd y chequeo de teclado matricial todo al mismo tiempo en un mismo ciclo

Feliz Día!

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re:Retardos sin usar delay_ms()
« Respuesta #11 en: 11 de Septiembre de 2016, 13:54:52 »
Sino deberias programarlo para que en tu loop principal solo continue cuando se active una bandera desde la interrupcion.

Supone esto:
Tenes algo que se tienen que ejecutar siempre y de forma continua, llamemoslo funcion_siempre()
Tenes una funcion que debe ser llamado cada 1ms, funcion_1ms()

Código: C
  1. int1 bandera;
  2.  
  3. void Int_Timer(void)
  4. {
  5.         bandera = 1;
  6. }
  7.  
  8.  
  9. void main(void)
  10. {
  11.  
  12.         // Setup
  13.  
  14.         while(1)
  15.         {
  16.                 funcion_siempre();
  17.                 if(bandera == 1)
  18.                 {
  19.                         funcion_1ms();
  20.                         bandera=0;
  21.                 }
  22.         }
  23. }

Tenes que darte cuenta que tanto esta solucion como la anterior dada por ALMNET, las funciones que tenes en el while nunca deberian superar el tiempo que da el timer.

Desconectado psyke

  • PIC10
  • *
  • Mensajes: 3
Re:Retardos sin usar delay_ms()
« Respuesta #12 en: 12 de Septiembre de 2016, 11:43:51 »
Agradezco mucho la respuesta de ambos. En los próximos días escribo si me aparecen nuevas dudas ya que tengo la pc rota, pero entendí la idea.
Se me había ocurrido algo de ese estilo, pero pensé: las sentencias que tenga dentro del while, siempre demoran lo mismo? En mi caso serán asignaciones de variables, cambiar la salida de un puerto del pic, incremento de variables, y ninguna otra operación rara.

Gracias de antemano