Autor Tema: como hacer un delay "no bloqueante" ??  (Leído 9874 veces)

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

Desconectado arcachofo

  • PIC16
  • ***
  • Mensajes: 126
    • Foro para usuarios Linux.
como hacer un delay "no bloqueante" ??
« en: 05 de Febrero de 2009, 01:43:49 »
Hola a todos, estoy haciendo algunas cosas con multitarea básica pero sin usar ningún RTOS, usando timer0+interrupciones para crear una base de tiempo, y en la rutina de interrupción una serie de contadores que activan cada tarea cuando ha pasado el tiempo establecido.

Trato de hacer algo como un "delay" pero que no mantenga el uso del procesador, sino con otro contador en interrupciones y cuando pase el tiempo del delay que vuelva al punto donde fué llamado... espero haberme explicado.

Este delay sería una función que activaría un contador y se quedaría en espera de que el contador levante la bandera de "fin de cuenta", entonces volvería al punto desde donde fué llamado el delay.

he hecho alguno específico para una tarea, pero me gustaría hacer uno que pudiera ser usado por cualquier otra tarea, lo que no tengo muy claro es como volver al punto desde donde fué llamado el delay, se puede hacer usando pcl y pclatch?
Si es así: cómo se haría esto?

Desconectado pibe

  • Colaborador
  • PIC24F
  • *****
  • Mensajes: 635
Re: como hacer un delay "no bloqueante" ??
« Respuesta #1 en: 05 de Febrero de 2009, 04:42:07 »
No entiendo muy bien lo que quieres hacer , pero a ver si acierto:

Hacer un delay en una salida cuando ocurre algo en una entrada sin que el micro se quede esperando sin hacer nada, no?

Pues si es así , cuando se origina el pulso en la entrada pones un flag a 1.
Si es un delay de retardo de 2 segundos antes de activar la salida ,por ejemplo :
Al entrar en las interrupciones (que se producen cada 10ms por ejemplo) miras si esa bandera está activada, si lo está sumas 1 a un contador nº1 , miras que no haya llegado a 100 (10msx100=1s) , si no ha llegado sales. Si ha llegado limpias el contador nº1 y le sumas 1 al contador nº2 (2x1s) y miras que no haya llegado a 2, si no ha llegado sales. Si ha llegado limpias el contador 2 y activas la salida y limpias el flag para que lo haga otra vez solo cuando vuelva a tener un pulso en la entrada.
Esto es algo somero, tampoco dices que lenguaje usas.
Mi jefe mirando el prototipo que estoy creando: "Y eso va a funcionar?"

Desconectado arcachofo

  • PIC16
  • ***
  • Mensajes: 126
    • Foro para usuarios Linux.
Re: como hacer un delay "no bloqueante" ??
« Respuesta #2 en: 05 de Febrero de 2009, 06:28:16 »
Hola pibe... gracias por la respuesta.

Si.. esa es la idea, el tema de los contadores y eso lo tengo hecho y funciona bién, pero solo me sirve para esa tarea en concreto, entonces el tema sería de alguna manera guardar el punto del programa donde se llama al delay y que cuando el delay termine, este direccione la ejecución otra vez a ese punto para que se siga ejecutando lo que viene después del delay.

El tema es que no sé como direccionar la ejecución al sitio que yo quiera, mirando por ahí creo entender que se puede hacer con pcl y pclath, pero nunca he hecho esto, lo más que he hecho es usar pcl para seleccionar opciones de una tabla.

Entonces este delay podría ser una subrutina, tendría que guardar la dirección desde donde se la llamó, y habilitar un contador con el valor que se le haya pasado y salir al bucle principal, donde se seguirían ejecutando otras tareas hasta que el contador del delay terminara, entonces se tendría que volver a la ejecución en el punto que se había guardado previamente. Esto es lo que no tengo nada claro.

El caso es hacer un delay de este tipo que pueda ser llamado desde cualquier sitio.. y el problema es como volver al sitio desde donde fué llamado...

Citar
Si ha llegado limpias el contador 2 y activas la salida y ......
En este caso "activar la salida" sería volver al punto donde se llamó el delay... ¿como hacer eso?

Estoy haciendo pruebas en Basic, pero lo del lenguaje a utilizar en principio es lo de menos.. con una idea general de la manera de proceder creo que me valdría para probar cosas...

Saludos

Desconectado arcachofo

  • PIC16
  • ***
  • Mensajes: 126
    • Foro para usuarios Linux.
Re: como hacer un delay "no bloqueante" ??
« Respuesta #3 en: 05 de Febrero de 2009, 06:58:04 »
Mira... lo que tengo es algo así (muy resumido):

Código: [Seleccionar]

bucle_principal:

    if flag_tarea1=1 then
        flag_tarea1=0
        ...........
        ...........
        habilita_demora=1
        tiempo_demora=100
        goto salir_tarea1
    volver_aqui:
        ...........
        ...........
    salir_tarea1   
    end if

goto bucle_principal


sub interrupt
   
    if habilita_demora=1 then
        tiempo_demora -= 1
        if tiempo_demora=0 then
            habilita_demora=0
            goto volver_aqui
        end if
    end if

End sub


Pero esa demora solo me sirve para la tarea1, lo que busco es hacer una demora que sea utilizable desde otras tareas (si está libre claro..)



Desconectado pibe

  • Colaborador
  • PIC24F
  • *****
  • Mensajes: 635
Re: como hacer un delay "no bloqueante" ??
« Respuesta #4 en: 05 de Febrero de 2009, 07:43:56 »
UY pues yo de basic me olvidé todo. Programo en asm.
Vamos a ver

Lo mejor que puedes hacer cuando comienzas con un programa, sea el lenguaje que sea es hacer un diagrama de flujo, sino te pierdes.
Un diagrama de flujo es un borrador donde planeas las decisiones del micro en modo gráfico. O sea con triangulos para decisiones si-no y rectángulos para ejecuciones, etc etc.
Yo SIEMPRE lo hago. Una vez tengo terminado el diagrama de flujo es cuestión de cocer y cantar, porque vas codificando lo que tienes en el diagrama de flujo y te puedo asegurar que tendrás poquísimos errores y además que si tienes que modificar algo lo haces en un periquete porque sabes que hace cada rutina.

tienes varias entradas y varias salidas retardadas?
Un ejemplo con 3 entradas + 3 relays

En el programa principal testeas las entradas 1 , luego la 2 y luego la 3 y pones el flag que le corresponda a 1 cuando se active. Sigues con mas instrucciones , lo que quieras hacer o vuelves al inicio.
En las interrupciones   testeas  flag 1, y si está activo entonces activas contador 1. Testeas  flag 2, y si está activo entonces activas contador 2. Testeas  flag 3, y si está activo entonces activas contador 3. AL finalizar cualquiera de los contadores activas la salida que le corresponda y limpias el flag que le corresponda.

No entiendo que quieres hacer con el pobre pcl /pclath :P
Si lo que quieres es que vuelva desde donde se le llamó te estás equivocando. Yo estaba con un proyecto donde "pensaba" que lo mejor era modificar el pcl para cuando volviese de las interrupciones fuese donde yo quisiera, pero inmediatamente lo descarté ya que se armaría un cacao que no veas.
Cuando las cosas parecen oscuras un simple "flag" me ha despejado todas las dudas.

Si pudieses ejemplificarme un poco más lo que quieres hacer, quisas pueda ayudarte mejor.
Mi jefe mirando el prototipo que estoy creando: "Y eso va a funcionar?"

Desconectado arcachofo

  • PIC16
  • ***
  • Mensajes: 126
    • Foro para usuarios Linux.
Re: como hacer un delay "no bloqueante" ??
« Respuesta #5 en: 05 de Febrero de 2009, 08:18:38 »
Citar
Lo mejor que puedes hacer cuando comienzas con un programa, sea el lenguaje que sea es hacer un diagrama de flujo, sino te pierdes.
Un diagrama de flujo es un borrador donde planeas las decisiones del micro en modo gráfico. O sea con triangulos para decisiones si-no y rectángulos para ejecuciones, etc etc.
Yo SIEMPRE lo hago. Una vez tengo terminado el diagrama de flujo es cuestión de cocer y cantar, porque vas codificando lo que tienes en el diagrama de flujo y te puedo asegurar que tendrás poquísimos errores y además que si tienes que modificar algo lo haces en un periquete porque sabes que hace cada rutina.
Si... es una buena idea, pero no estoy haciendo una aplicación concreta, sino buscar la manera de hacer una rutina que pueda aplicar en distintas ocasiones,

Si programas en asm estupendo... he encontrado algo que se parece a lo que yo quiero,... lo siento pero usa pcl y pclath... no se me ocurre otra manera.
El tema sería una macro que guarde el punto donde tiene que retornar cuando termine el contador, algo así:

Código: [Seleccionar]

demora macro tiempo

MOVF tiempo,W
MOVWF tiempo_demora ;valor del contador de demora
BSF habilita_demora ;flag que activa el contador de demora (definido anteriormente)
MOVLW HIGH($+.5)
MOVWF vuelve_aqui_H
MOVLW LOW($+.3)
MOVWF vuelve_aqui
goto bucle_principal

endm


Cuando termina el contador vuelve al punto donde guardado en las variables "vuelve_aqui_H" y "vuelve_aqui":

Código: [Seleccionar]
sub interrupt
   
    if habilita_demora = 1 then
        tiempo_demora -= 1
        if tiempo_demora = 0 then
            habilita_demora = 0
            PCLATCH = vuelve_aqui_H
            PCL = vuelve_aqui
        end if
    end if

End sub

Podría funcionar esto?

Desconectado pibe

  • Colaborador
  • PIC24F
  • *****
  • Mensajes: 635
Re: como hacer un delay "no bloqueante" ??
« Respuesta #6 en: 05 de Febrero de 2009, 08:27:25 »
Pero es que lo estás haciendo al revés. A ver

Los contadores y activaciones ponlos en las interrupciones y en el principal pon los test de entradas. Es así de fácil. A menos que no entienda claramente lo que tienes en mente.
Mi jefe mirando el prototipo que estoy creando: "Y eso va a funcionar?"

Desconectado arcachofo

  • PIC16
  • ***
  • Mensajes: 126
    • Foro para usuarios Linux.
Re: como hacer un delay "no bloqueante" ??
« Respuesta #7 en: 05 de Febrero de 2009, 09:13:30 »
Citar
Pero es que lo estás haciendo al revés. A ver

Los contadores y activaciones ponlos en las interrupciones y en el principal pon los test de entradas. Es así de fácil. A menos que no entienda claramente lo que tienes en mente.

Si... tienes razón, no puedo poner el salto dentro de las interrupciones, entonces sería algo así:

Código: [Seleccionar]

bucle_principal:

    if flag_regreso_demora = 1
        flag_regreso_demora = 0
        PCLATCH = vuelve_aqui_H
        PCL = vuelve_aqui           'Aquí debería saltar a: "RETORNO".. no?
    end if

    if flag_tarea1 = 1 then
        flag_tarea1 = 0
        ...........
        ...........
        demora 100       'llama a la macro "demora" con el parámetro 100
        ...........         'RETORNO
        ...........   
    end if

goto bucle_principal


sub interrupt
   
    if habilita_demora = 1 then
        tiempo_demora -= 1
        if tiempo_demora = 0 then
            habilita_demora = 0
            flag_regreso_demora = 1
        end if
    end if

End sub


demora macro tiempo

MOVF tiempo,W
MOVWF tiempo_demora ;valor del contador de demora
BSF habilita_demora ;flag que activa el contador de demora (definido anteriormente)
MOVLW HIGH($+.5)
MOVWF vuelve_aqui_H
MOVLW LOW($+.3)
MOVWF vuelve_aqui
goto bucle_principal

endm


El compilador GCBasic acepta asm directamente, no he probado con macros, pero eso ya es otra cuestión; lo que me interesa es si esa manera de usar pcl y pclatch podría funcionar...


Desconectado pibe

  • Colaborador
  • PIC24F
  • *****
  • Mensajes: 635
Re: como hacer un delay "no bloqueante" ??
« Respuesta #8 en: 05 de Febrero de 2009, 09:20:38 »
lo que me interesa es si esa manera de usar pcl y pclatch podría funcionar...

No entiendo por que te empecinas en abusar sexualmente de los pobres registros  :mrgreen:

No puedes hacerlo como yo te he dicho? No te sirve o tienes otra cosa en mente?
Mi jefe mirando el prototipo que estoy creando: "Y eso va a funcionar?"

Desconectado arcachofo

  • PIC16
  • ***
  • Mensajes: 126
    • Foro para usuarios Linux.
Re: como hacer un delay "no bloqueante" ??
« Respuesta #9 en: 05 de Febrero de 2009, 10:31:22 »
Citar
No entiendo por que te empecinas en abusar sexualmente de los pobres registros
 

...Es que nunca me he hecho un trío con pcl y pclath.... y me han dicho que son la caña!!! así que lo quiero probar como sea... :-)


Citar
No puedes hacerlo como yo te he dicho? No te sirve o tienes otra cosa en mente?

Si.. algo así es lo que tengo, osea crear un retardo para cada tarea que lo necesite, pero soy tan vago que prefiero aprender a manejar pcl y pclatch con tal de no estar escribiendo lo mismo varias veces...  :lol:

No... hablando en serio, la idea es primero aprender a manejar estos registros, ahora que sé que se pueden usar para esto me ha picado la curiosidad; y luego hacer algún macro o función o algo que pueda servir para llamarlo desde cualquier punto de cualquier tarea; quizás hacer 3 retardos de estos de uso general que puedan ser utilizados en cualquier momento por cualquier tarea, con la limitación de que solo pueden haber 3 retardos funcionando a la vez, pero podrían haber 10 o 15 posibles llamadas a retardos desde distintos sitios y cada uno debería continuar desde donde fué llamado, si tengo que crear 15 retardos con sus flags y sus salidas correspondientes puedo acabar como el muñeco animado que tienes en tus mensajes.. :D

El primer problema que me encuentro es el del direccionamiento al punto desde donde se llamó el retardo, luego tendré que resolver el tema de buscar un temporizador libre y luego... pués lo que venga, al fin y al cabo se trata de aprender...

Saludos y gracias por el interés.

Desconectado reiniertl

  • Moderadores
  • PIC24H
  • *****
  • Mensajes: 1187
Re: como hacer un delay "no bloqueante" ??
« Respuesta #10 en: 05 de Febrero de 2009, 11:06:53 »
Yo mejor me iría directo a utilizar un RTOS, porque ya pasé por eso y la solución evidente fue utilizar RTOS, así que aprendí y me ha gustado tanto que no me hayo sin RTOS.

Desconectado arcachofo

  • PIC16
  • ***
  • Mensajes: 126
    • Foro para usuarios Linux.
Re: como hacer un delay "no bloqueante" ??
« Respuesta #11 en: 05 de Febrero de 2009, 11:39:01 »
Hola reiniertl...

Si... llega un punto en que se hace necesario, pero me gusta la artesanía y comprender como funcionan las cosas, con un RTOS es todo más facil, pero no sabes lo que está pasando, sobre todo si no es de código abierto.

Lo que estoy haciendo es "multitarea" o algo parecido muy básico, pero me permite hacer cosas que son imposibles en la programación puramente secuencial. Nosé si para esto vale la pena el gasto de recursos que supone un RTOS; aunque mientras haya memoria seguro que vale la pena en el sentido de facilitar la tarea de programar y de las posiblidades que ofrece.

Lo que si estoy viendo es que las posiblidades que abre esto son muy grandes, simplemente con timer0+interrupciones, unos pocos contadores y dividiendo las tareas en partes sencillas se pueden hacer cosas interesantes; por ejemplo, antes tenía un programa que leía unos canales ADC, hacía unos cálculos, movía unos motores según los cálculos y enviaba una cadena de datos por uart a 9600 b,... total.. el ciclo se repetía muy pocas veces por segundo.
Ahora puedo elegir cada cuanto tiempo se hace cada cosa, y aunque enviar los datos por uart tarda casi 20 ms, puedo leer adc cada 1 ms si quiero, hacer los cálculos con la media de 10 lecturas y actualizar los motores cada 10 ms, todo esto con un oscilador de 4 MHz.

Por cierto... he estado viendo tus explicaciones sobre RTOS tanto por aquí como en ucontrol,.. y me están siendo muy útiles, aunque yo no uso CCS pero los conceptos me van quedando algo más claros... gracias.


Saludos.

Desconectado dogflu66

  • Moderadores
  • DsPIC30
  • *****
  • Mensajes: 3510
Re: como hacer un delay "no bloqueante" ??
« Respuesta #12 en: 05 de Febrero de 2009, 12:32:56 »
Saludos desde Granada, España.

Desconectado RICHI777

  • Colaborador
  • PIC24H
  • *****
  • Mensajes: 1498
Re: como hacer un delay "no bloqueante" ??
« Respuesta #13 en: 05 de Febrero de 2009, 12:48:03 »
Hola, lo queres hacer en lenguaje se hace utilizando las funciones setjmp y longjmp ( que serian algo asi como un no local goto ) .

Saludos !

Desconectado arcachofo

  • PIC16
  • ***
  • Mensajes: 126
    • Foro para usuarios Linux.
Re: como hacer un delay "no bloqueante" ??
« Respuesta #14 en: 05 de Febrero de 2009, 13:46:23 »
dogflu66: pues ese estilo de programación con base de tiempo es lo que estoy probando, aunque respecto a los delays, los que he visto en tus ejemplos están basdos en timers, pero creo que siguen siendo "bloqueantes"... no?...osea el programa se para ahí hasta que termina el delay.

Lo que trato es de evitar todos esos tiempos de espera no-útiles; por ejemplo las funciones de enviar una cadena de texto por uart se pasan el 99,999999% del tiempo solo esperando, quitando la parte de gestionar el dato que se vá a enviar, todo que hay que hacer es esperar a que TXIF esté alto y poner el dato en TXREG, y no es necesario quedarse esperando por TXIF, que además vá a tardar varios cientos o miles de ciclos de instrucción en quedar libre... con comprobarla de vez en cuando ya nos vale...

Para que sirve que el pic tenga uart por hardware si nos vamos a quedar esperando el mismo tiempo que si lo hiciéramos por software... habrá que aprovechar las capacidades del pic... no?

RICHI777: gracias por el dato, esas funciones a que compilador o lenguaje pertenecen?