RTOS, multitarea, o como aprobechar el tiempo de proceso.

Ver el tema anterior Ver el tema siguiente Ir abajo

RTOS, multitarea, o como aprobechar el tiempo de proceso.

Mensaje por Pikitin el Dom 1 Feb 2009 - 1:43

Es habitual en cualquier programa para micros usar "delays", esperar a que un canal ADC obtenga un dato o a que una linea USART espere ciertos tiempos par enviar o recibir cada bit, de manera que en cuanto ponemos dos o tres tareas a funcionar nos topamos con que eso va cada vez más lento y en muchos casos es imposible mantener la velocidad o frecuencia mínima de operación que nos gustaría para cada tarea. La solución típica es ir a un oscilador más rápido, pero cuando llegamos al máximo parece que hemos llegado al limite de la capacidad del pic, cuando en realidad es muy posible que solo estemos utilizando un 10% util (incluso mucho menos) del tiempo de proceso del micro.

Si viéramos la actividad util del pic, observaríamos que la mayor parte del tiempo no está haciendo nada... solo esperar a que algo termine; para aprovechar mejor el tiempo de proceso del pic se usan los llamados RTOS (Real Time Operating System), de manera que el pic pueda actuar como lo hace cualquiera de nuestros PCs, pareciendo que hace varias cosas al mismo tiempo... en realidad lo único que hace es aprobechar los tiempos de espera para hacer otras cosas.

La base de los RTOS no es más que un control de tiempo, osea implementar algún tipo de "reloj" que controle el tiempo que va pasando, entonces si por ejemplo queremos un led parpadeando cada 500 mS, no usaríamos un delay, sino que se iría mirando cada cierto tiempo a ver si ya han pasado los 500 mS, pero mientras tanto podría hacer otras cosas.

Esto incluso se podría aplicar a una transmision o recepcion USART, dependiendo del baudrate y la frecuencia del pic; en los casos de transmisones no muy rápidas y velocidades altas de oscilador, estos tiempos entre bit y bit son largísimos vistos desde el punto de vista el procesador, perdiendo cientos de ciclos de instrucciones que podrían utilizarse.

Estos cortos periodos de tiempo mientras trabaja el hardware externo al procesador son aprobechables, aunque algo más complicados de implementar, pero realizar tareas cada cierto tiempo sin usar delays o ese tipo de cosas es realmente sencillo y es lo que hacen la mayoría de los llamados RTOS para PIC que se suelen ver por ahí; no es más que implementar un "reloj" con algún timer que provoque una interrupción cada cierto tiempo; en la rutina de interrupciones hay una serie de contadores (uno para cada tarea) que se van incrementando en cada interrupción, si un contador llega al valor establecido para esa tarea, entonces activa un flag de tarea activada, una vez actualizados todos los contadores sale de interrupciones.
La parte principal del programa solo es un bucle infinito que compruebe continuamente esos flags de tarea activada, cuando encuentra un flag en alto salta a la subrutina que realiza la tarea correspondiente.

De esta manera es facil realizar varias tareas "en paralelo", siempre que sean tareas no demasiado largas, y hay que definir cada cuanto tiempo se deben realizar esas tareas.

La ventaja además de permitir una mayor "actividad" del pic, es que por ejemplo se puede decir: lee un canal ADC cada 10 ms, calcula la media de las últimas 10 lecturas cada 100 ms, actualiza pwm según la media de ADC cada 200 ms, manda los datos por UART cada 500 ms... etc.... Tenemos control facilmente de la frecuencia con que se hace cada tarea, cosa que es complicada cuando programamos normalmente, ya que los tiempos cambian cada vez que cambiamos algo en el programa.

Me parece que es algo muy interesante y casi imprescindible si queremos hacer varias tareas cada cierto tiempo sin volvernos locos...

Alguien ha experimentado con estas cosas??... que les parece esto?



Saludos.


Última edición por Pikitin el Dom 1 Feb 2009 - 8:30, editado 1 vez

Pikitin
veterano
veterano

Mensajes : 623
Fecha de inscripción : 26/11/2008

http://linuxmicros.blogspot.com/

Volver arriba Ir abajo

Ejemplo de multitarea en un pic16f876 y GCBasic

Mensaje por Pikitin el Dom 1 Feb 2009 - 8:23

Ejemplo básico de multitarea: dos leds parpadeando a distinta velocidad.

Este programita muestra una manera sencilla de afrontar multitareas utilizando el timer0, el "tiempo base del sistema" es de 1ms, aunque seguramente con 500 us o menos es suficiente para realizar varias tareas, pero 1 ms es una base facil de usar para este ejemplo.

Un led parpadea a un ritmo se 2 s , 1s encendido y 1s apagado, el otro a un rimo de 600 ms, 300ms cada estado.

Este es el código en GCBasic:

Código:

'_______________________________________________________________________
'
'
'      Multitarea: Dos leds parpadeando a distinta velocidad
'
'_______________________________________________________________________


'------------------------- CONFIGURAR MICRO -----------------------------
'------------------------------------------------------------------------

#chip 16F876, 4      'modelo de pic y velocidad de reloj

#config HS_OSC, WDT_OFF, LVP_OFF, BODEN_OFF, PWRTE_ON


'--------------------------- DEFINICIONES -------------------------------
'------------------------------------------------------------------------ 

#define LED1 PORTB.0
#define LED2 PORTB.2

'----------------------- CONFIGURAR VARIABLES ---------------------------
'------------------------------------------------------------------------

dim t_led1 as word          'tiempo de parpadeo led1
dim c_led1 as word          'contador led1
f_led1 = 0                  'flag led1

dim t_led2 as word          'tiempo de parpadeo led2
dim c_led2 as word          'contador led2
f_led2 = 0                  'flag led2

'------------------------- CONFIGURAR PUERTOS ---------------------------
'------------------------------------------------------------------------
 
    TRISA = b'000001'
    TRISB = b'00000000'
    TRISC = b'10000000'

    PORTA = b'000000'
    PORTB = b'00000000'
    PORTC = b'00000000'
 
'----------------------------- PRINCIPAL --------------------------------
'------------------------------------------------------------------------

OPTION_REG = b'10000001'      'Timer0 configurado para 1 ms con Fosc=4MHz (prescaler 1/4)

bsf INTCON,T0IE                'Interrupciones Timer0 habilitadas

t_led1 = 1000                  'Tiempo de tarea led1
t_led2 = 300                  'Tiempo de tarea led2

c_led1 = 0
c_led2 = 0

do

    if f_led1 = 1 then call tarea_led1

    if f_led2 = 1 then call tarea_led2

loop


'--------------------------- INTERRUPCIONES -----------------------------
'------------------------------------------------------------------------

Sub interrupt

    if INTCON.T0IF = 1 then        'si la interrupcion es de timer0

        TMR0 = 5                    'necesitamos una cuenta de 250: 5 a 255

        c_led1 += 1                'incrementar contador de tarea

        if c_led1 > t_led1 then    'si ha pasado el tiempo establecido
            c_led1 = 0              'borrar contador
            f_led1 = 1              'subir flag de tarea
        End if

        c_led2 += 1

        if c_led2 > t_led2 then
            c_led2 = 0
            f_led2 = 1
        End if

    End if

    INTCON.T0IF = 0
End Sub

'------------------------ SUBRUTINAS DE TAREAS --------------------------
'------------------------------------------------------------------------
Sub tarea_led1

    f_led1 = 0

    if LED1 = 1 then
        LED1 = 0
        exit Sub
    End if

    LED1 = 1

End Sub


Sub tarea_led2

    f_led2 = 0

    if LED2 = 1 then
        LED2 = 0
        exit Sub
    End if

    LED2 = 1

End Sub


Pikitin
veterano
veterano

Mensajes : 623
Fecha de inscripción : 26/11/2008

http://linuxmicros.blogspot.com/

Volver arriba Ir abajo

Re: RTOS, multitarea, o como aprobechar el tiempo de proceso.

Mensaje por jpic el Dom 1 Feb 2009 - 13:20

que tal pikitin, me entusiasma el tema del RTOS, pero no he tenido tiempo para dedicarle.
considero que es una herramienta muy valiosa para desarrollar procesos multitarea, el compilador CCS que uso tiene uno propio puedes ver una muy buena info al respecto aqui.
avatar
jpic
Participante Activo
Participante Activo

Mensajes : 34
Fecha de inscripción : 15/12/2008
Localización : Colombia

Volver arriba Ir abajo

Re: RTOS, multitarea, o como aprobechar el tiempo de proceso.

Mensaje por Pikitin el Lun 2 Feb 2009 - 4:47

Gracias por el link jpic, muy buena y extensa información la del amigo reinier.

Aunque yo no no uso CSS, el RTOS que trae se vé que tiene muchas posiblidades, pero para dominarlo hay que echarle horas... me había pasado un par de veces que intenté manejar el RTOS de SourceBoost, que al final lo dejaba para otro dia que tubiera más tiempo; pero hace unos días encontré un ejemplo de "multiproceso" muy sencillo y al fin entendí lo que hace basicamente un RTOS, y me dí cuenta que para hacer multiproceso básico no hace falta tener instalado ningún RTOS.

El ejemplo que puse en mi mensaje anterior se podría decir que es el RTOS más simple posible; no es más que establecer una base de tiempo, esto se consigue con un timer y las interrupciones. Solo hay que poner en la subrutina de interrupciones un contador para cada tarea y establecer en que valor del contador se ejecuta esa tarea.

Solo con esto ya se pueden conseguir muchas cosas, por ejemplo dos leds parpadeando simultaneamente a distintas velocidades; lo bueno de esto es que ahora le puedo añadir más tareas sin afectar a las que ya están, por ejemplo podría tranquilamente añadir otros 10 leds parpadeando cada uno a velocidades distintas, luego si quiero le puedo añadir otras tareas.

Por ejemplo el siguiente paso en mis experimentos ha sido añadir una tarea que es mandar una frase por UART, la cual veo por la misma terminal serie (gtkterm) que utilizo para grabar el programa (Bootloader/monitor de Jack-per) .

Pero la tarea de mandar una frase de 30 o 40 caracteres a 9600 baud. ocupa bastantes ms, entonces esto podría retrasarnos otras operaciones que tubieran que ejecutarse cada pocos ms; por ejemplo en una prueba que hice, ajusté el "tiempo base" a 200 us y puse el led2 para que parpadeara cada 1 ms (5 ciclos) y añadí la tarea de mandar una frase larga por uart cada 4 seg; el led2 se debería ver siempre encendido pero a mitad de potencia.. y así es, pero cada 4 seg se vé un parpadeo, que corresponde al momento en que la frase es enviada por uart; osea una tarea larga está afectando a una que se debe ejecutar muy rapidamente.

Entonces podríamos aprobechar nuestro "sistema multiproceso" y dividir esta tarea larga en otras sub-tareas, de manera que solo se use el tiempo de procesador estrictamente necesario, por ejemplo no quedarse esperando a que la linea esté libre, sino cargar el dato a mandar en una variable y añadir una subrutina en las interrupciones que compruebe en cada ciclo si la linea está libre y mande el dato, de esta manera el programa nunca se queda esperando.

Así se pueden añadir tareas largas que en realidad lo que hacen es pasarse la mayor parte del tiempo esperando, por ejemplo ADC, LCD y otras... La limitación (y una diferencia con un verdadero RTOS) es que dos tareas no pueden llamar al mismo recurso a no ser que lo tengamos muy planeado. Por ejemplo, en la tarea led1 añadí una linea para que mandara por uart el tiempo que había pasado desde la última interrupción, pero como las dos tareas coinciden en algunos momentos pues los mensajes quedaban cortados y se producían algunos efectos curiosos que todavía no entiendo, el caso es que las dos tareas estaban accediendo a la linea serie a la vez y se producía un conflicto y un mal funcionamiento.

Hay maneras de solucionar esto, pero por ahora nos quedamos con que solo una tarea manda cosas por uart...

Pues ahí va el mismo ejemplo de antes pero con la tarea "mandar_frase" añadida, ejecutándose a la vez que un led a 1ms sin afectar a este:

Código:
  '_______________________________________________________________________
'
'
'      Multitarea: Dos leds parpadeando a distinta velocidad
'                y una frase enviada por UART
'
'_______________________________________________________________________


'------------------------- CONFIGURAR MICRO -----------------------------
'------------------------------------------------------------------------

#chip 16F876, 4      'modelo de pic y velocidad de reloj

#config HS_OSC, WDT_OFF, LVP_OFF, BODEN_OFF, PWRTE_ON


'--------------------------- DEFINICIONES -------------------------------
'------------------------------------------------------------------------ 

#define LED1 PORTB.0
#define LED2 PORTB.2
'#define baudrate 9600

'----------------------- CONFIGURAR VARIABLES ---------------------------

'------------------------------------------------------------------------

dim t_led1 as word          'tiempo de parpadeo led1
dim c_led1 as word          'contador led1
f_led1 = 0                  'flag led1

dim t_led2 as word          'tiempo de parpadeo led2
dim c_led2 as word          'contador led2
f_led2 = 0                  'flag led2

dim t_frase as word        'tiempo de enviar frase
dim c_frase as word        'contador enviar frase
f_frase = 0                'flag enviar frase


'------------------------- CONFIGURAR PUERTOS ---------------------------
'------------------------------------------------------------------------
 
    TRISA = b'000001'
    TRISB = b'00000000'
    TRISC = b'10000000'
   
    PORTA = b'000000'
    PORTB = b'00000000'
    PORTC = b'10000000'
 
'----------------------------- PRINCIPAL --------------------------------

'------------------------------------------------------------------------
dim  mensaje(35)
mensaje$ = "esto es una prueba de multitarea"

'InitUSART 'No es necesaria si se usa el Bootloader, usart ya está funcionando

InitTimer0 Osc, PS0_1/2        'Timer0 configurado para 200 us con Fosc=4MHz   
TMR0 = 155
set INTCON.T0IE on            'Interrupciones Timer0 habilitadas

t_led1 = 10000                'Tiempo de tarea led1
t_led2 = 5                    'Tiempo de tarea led2
t_frase = 20000                'Tiempo de tarea mandar frase


do                              'Bucle principal: se comprueban los flags

    if f_led1.0  on then call tarea_led1
    if f_led2.0  on then call tarea_led2
    if f_frase.0 on then call manda_frase mensaje
    if f_dato.0  on then call manda_dato
loop


'--------------------------- INTERRUPCIONES -----------------------------
'------------------------------------------------------------------------

Sub interrupt

    if INTCON.T0IF on then        'si la interrupcion es de timer0

        TMR0 = 155                  'necesitamos una cuenta de 100: 155 a 255

        c_led1 += 1                'incrementar contador de tarea
        if c_led1 > t_led1 then    'si ha pasado el tiempo establecido
            c_led1 = 0              'borrar contador
            f_led1 = 1              'subir flag de tarea
        End if

        c_led2 += 1
        if c_led2 > t_led2 then
            c_led2 = 0
            f_led2 = 1
        End if

        c_frase += 1
        if c_frase > t_frase then
            c_frase = 0
            f_frase = 1
        End if
    End if

    if transmite.0 on then    'transmite un dato por UART si su bandera está activada
        if PIR1.TXIF on then  'comprueba linea libre, sinó sale
            TXREG = dato
            transmite = 0
        End if
    End if

    INTCON.T0IF = 0          'borrar flag Timer0

End Sub

'------------------------ SUBRUTINAS DE TAREAS --------------------------
'------------------------------------------------------------------------

Sub tarea_led1
    f_led1 = 0
    if LED1 on then
        LED1 = 0
        exit Sub
    End if
    LED1 = 1
End Sub


Sub tarea_led2
    f_led2 = 0
    if LED2 on then
        LED2 = 0
        exit Sub
    End if
    LED2 = 1
End Sub


Sub manda_frase (In frase$) 

    largo = frase(0)
    if largo = 0 Then exit Sub
    f_dato = 1                      'sube flag de tarea manda_dato
    caracter = 1
    f_frase = 0                    'Borra flag de manda_frase

End Sub


Sub manda_dato

    if transmite.0 on then exit Sub 'si todavía no ha mandado la letra anterior

    if caracter > largo then        'si yá mandó todas las letras
        dato = 0x0A                'Retorno de carro
        transmite = 1
        f_dato = 0                  'Borra flag de manda_dato
        exit Sub
    End if
    dato = frase(caracter)
    transmite = 1
    caracter += 1

End Sub
   

Pikitin
veterano
veterano

Mensajes : 623
Fecha de inscripción : 26/11/2008

http://linuxmicros.blogspot.com/

Volver arriba Ir abajo

Re: RTOS, multitarea, o como aprobechar el tiempo de proceso.

Mensaje por Geo el Lun 2 Feb 2009 - 19:21

Esta manera de trabajar mediante "banderas" es algo similar a la manera de trabajar de las interrupciones del microcontrolador Smile.

Solo he hecho un par de cosas similares en un HC08 de Freescale, ahora mismo me encuentro planeando cómo implementarlo en la aplicación de mi proyecto, aunque no es lo más urgente Razz.

Gracias por la información Smile.

Geo
Participante Activo
Participante Activo

Mensajes : 92
Fecha de inscripción : 16/12/2008
Localización : México

http://hsblog.mexchip.com

Volver arriba Ir abajo

Re: RTOS, multitarea, o como aprobechar el tiempo de proceso.

Mensaje por Pikitin el Lun 2 Feb 2009 - 21:19

Si... va todo por banderas, y es lo más complicado, sobre todo cuando tienes varios procesos con sub-procesos que se pueden estar ejecutando a la vez. Las banderas son las que organizan la ejecución de cada tarea y pueden llegar a ser un dolor de cabeza, pero esta manera de programar permite conseguir cosas que es imposible conseguir usando programacion "secuencial", donde cada tarea se ejecuta solo cuando la anterior ha terminado.

Ahora estoy añadiendo unas lecturas ADC, que es otro caso que tiene cierta complicación, porque para leer cada canal hacen falta varios sub-procesos simples: abrir canal, iniciar conversión y leer valor; hay que ir subiendo y bajando banderas según se va realizando cada proceso para que en el siguiente ciclo se sepa donde tiene que seguir... al menos yo lo estoy haciendo así:

if bandera_tarea1 on then
...........if bandera sub_tarea1_1 then
.....................call sub_tarea1_1
.....................goto salir_tarea_1

...........if bandera sub_tarea1_2 then
.....................call sub_tarea1_2
.....................goto salir_tarea_1

...........if bandera sub_tarea1_3 then
.....................call sub_tarea1_3

salir_tarea_1:

De todas formas lo de las banderas es la manera de activar o desactivar tareas en cada ciclo, pero detrás de todo eso tiene que haber una base de tiempo que determine cuando se hace cada cosa, esa es la clave de esta manera de programar: timer + interrupciones para crear una base de tiempo...

Ya nos contarás algo de tus proyectos... no?

Saludos.

Pikitin
veterano
veterano

Mensajes : 623
Fecha de inscripción : 26/11/2008

http://linuxmicros.blogspot.com/

Volver arriba Ir abajo

Re: RTOS, multitarea, o como aprobechar el tiempo de proceso.

Mensaje por Pikitin el Miér 4 Feb 2009 - 5:37

Pues está interesante esta manera de programar, se gana mucho en flexiblidad; cuesta un poco más poner en marcha el sistema, pero una vez que lo tienes puedes jugar con el tiempo base y las frecuencias de ejecución de cada tarea.

Se puede uno complicar más o menos... por ejemplo lo de dividir las lecturas ADC al final he visto que no vale la pena, ya que todo el proceso se hace muy rápido, sin embargo las transmisiones por UART son muy lentas y se gana un montón haciéndolas por multitarea.

Por ejemplo en las últimas pruebas que hice se leen 3 canales ADC 1000 veces por segundo y se envían los datos por uart a liberlab cada 20 ms, esto con programación "secuencial" sería imposible, ya que cada transmisión de una cadena de datos tarda casi 20 ms, sería imposible hacer esto y a la vez leer 3 canales ADC 1000 veces por segundo.

Liberlab está siendo una herramienta muy util, está pensada para representar datos de ADC, pero en realidad representa cualquier valor que reciba, sean los que sean; así que lo estoy usando para mandarle los tiempos que tardan las tareas en realizarse, de esta forma veo graficamente como está funcionando la cosa.

Como ejemplo aquí podemos ver como con una base de tiempo suficientemente larga todo funciona bien:





Y aquí con una base de tiempo muy corta la cosa cambia, de hecho el pic se "cuelga" de vez en cuando... puede estar funcionando un par de minutos o 30 segundos, pero al final se suele quedar bloqueado... no sé muy bién porqué, pero deja de funcionar:




El proceso azul es la transmisión de datos por uart y el verde la lectura adc, aunque están en escalas distintas, el de uart está medido en ciclos de contador, ya que es mucho más largo y el adc está medido en ciclos del timer, ya que tarda menos de 1 ciclo de contador. la linea blanca es un canal adc conectado a un potenciómetro para comprobar que el adc funciona.

Así puedo experimentar con distintos valores de tiempo base y frecuencias de tareas, así como desfasando las tareas o programando de otra manera y puedo ver graficamente la estabilidad del sistema.

Estaba pensando que incluso podría poner una especie de monitor de "carga" del procesador: si pongo un contador que se incremente cada vez que se realiza una tarea o algo así y con algun cálculo podría ver cual es la carga real del procesador.
Veo que el liberlab tiene la opción de aplicar funciones matemáticas a los valores de entrada... pero todavía no se como vá esto...


Saludos.

Pikitin
veterano
veterano

Mensajes : 623
Fecha de inscripción : 26/11/2008

http://linuxmicros.blogspot.com/

Volver arriba Ir abajo

Re: RTOS, multitarea, o como aprobechar el tiempo de proceso.

Mensaje por ciccero el Sáb 11 Jul 2009 - 0:10

Buenas Pikitin, la verdad muy buena tu explicación de sistema multitarea, sencillo y fácil de entender, como lo comente en mi presentación que hice hace varios minutos....jeje. Todavía no empiezo a programar en forma PIC en Linux pero hoy empiezo....jejeje.
Espero presentar algo pronto, a ver si este fin de semana puedo publicar algo sencillo.

Solo como comentario adicional al los sistemas multitareas en la mayoria de los microntroladores si no es que en todos cuentan con interrupciones para ciertas tareas específicas como lo son: UARTs, ADC, output compare (para hacer PWM), input compare (para medir frecuencia en señales) por mencionar algunas, dependiendo del microcontrolador utilizado tendra más o menos interrupciones de hardware, por lo que se pueden utilizar y asi eliminar unas cuantas banderas, el problema de esto es que nuestro código estará limitado o amarrado a ese procesador específico.


bueno luego sigo comentado mas....ya me tengo que ir....jejeje


atte.
ciccero

ciccero
Participante
Participante

Mensajes : 11
Fecha de inscripción : 10/07/2009

Volver arriba Ir abajo

Re: RTOS, multitarea, o como aprobechar el tiempo de proceso.

Mensaje por Pikitin el Sáb 11 Jul 2009 - 12:00

Si... bueno, empecé el tema con el título "Rtos... etc", pero en realidad de lo que hablo no es un verdadero rtos, "multitarea" quizás sea mas conveniente, aunque la verdad no sé cual sería la terminología correcta. Quizás: programar con bases de tiempo...

Si, el hardware del micro ya es en sí un sistema de multitarea pero por hardware, pero esta manera de programar se puede aplicar sobre todo para que ciertos procesos no utilicen tiempo de procesador si no es necesario, por ejemplo delays y ese tipo de cosas; y para ejecutar cada tarea solo con la frecuencia que es necesaria, a veces no hace falta estar repitiendo un proceso continuamente sino ejecutarlo cada x milisegundos o incluso cada x segundos. Aunque la verdad es que ahora casi todo lo hago de esta manera, ya que es muy sencillo añadir o quitar "tareas" sin que esto afecte a las demás, cambiar la frecuencia de ejecución, etc.

Pero al final es un lío de banderas, contadores, etc ; así que me hice una librería que simplifica mucho la cosa.
Ultimamente estoy programando casi todo en GcBasic, así que hice la librería para este compilador:
http://pic-linux.forosactivos.net/gcbasic-f26/librerya-para-multitarea-en-gcbasic-t132.htm

Pues nada, ánimo con tus proyectos, ya nos contarás.

Saludos.

Pikitin
veterano
veterano

Mensajes : 623
Fecha de inscripción : 26/11/2008

http://linuxmicros.blogspot.com/

Volver arriba Ir abajo

Re: RTOS, multitarea, o como aprobechar el tiempo de proceso.

Mensaje por Contenido patrocinado


Contenido patrocinado


Volver arriba Ir abajo

Ver el tema anterior Ver el tema siguiente Volver arriba


 
Permisos de este foro:
No puedes responder a temas en este foro.