Principio de multitarea. Desterrando a los delays.

#1
Este artículo tiene como base proponer una metodología para efectuar programas multitarea en microcontroladores usando el compilador CCS PicC.

Todo está en función de un temporizador y la directiva #use timer, no se hace uso de las interrupciones ya que estas estarán reservadas para tareas de mayor prioridad.

La directiva #use timer.
Esta directiva crea un timer tick usando uno de los temporizadores del Pic. El timer tick es inicializado a cero al iniciar el programa. Esta directiva crea una constante con nombre TICKS_PER_SECOND que especifica el número de ticks que ocurren en un segundo.

… mayor información en el help de CCS PicC.

La rutina principal main(), se convertirá en el lanzador de tareas y las tareas serán funciones.

Este modo es ideal para las tareas repetitivas, mientras que las secuenciales requieren algunos “trucos”.

Este método lo vi en uno de los ejemplos que CCS tiene disponible.

#use timer(timer=1,tick=10ms,bits=16,noisr)

Usa el temporizador 1, tick cada 10 milisegundos, tamaño de los ticks 16 bits, no se usa interrupción para actualizar los ticks.

Ejemplo.
Generar el parpadeo de tres leds, el primero con un periodo de 100ms, el segundo con en periodo de 300ms y el tercero con un periodo de 1s.

Es importante que el tiempo mínimo de repetición de la tarea sea mayor o igual a tick usado en el use timer.

En el archivo main.h
C:
/*****************************************************************************/
#include <16F628A.h>
/*****************************************************************************/
#FUSES NOWDT                    //
#FUSES PUT                      //Power Up Timer
#FUSES MCLR                     //Master Clear pin enabled
#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 NOPROTECT                //Code not protected from reading
/*****************************************************************************/
#use delay(internal=4MHz)
/*****************************************************************************/
#use timer(timer=1,tick=10ms,bits=16,noisr)
/*****************************************************************************/
En el archivo main.c.
C:
*****************************************************************************/
#include <main.h>
/*****************************************************************************/
void tarea1()
{
   output_toggle(pin_a0);  //cambia de estado el bit 0 del puerto A
}
/*****************************************************************************/
void tarea2()
{
   output_toggle(pin_a1);  //cambia de estado el bit 1 del puerto A
}
/*****************************************************************************/
void tarea3()
{
   output_toggle(pin_a2);  //cambia de estado el bit 2 del puerto A
}
/*****************************************************************************/
void main()
{
   unsigned int16 tick,tick_tarea1=0,tick_tarea2=0,tick_tarea3=0;
   while(true)                                //bucle infinito
   {
      tick=get_ticks();     //lee el valor actual de los ticks
      if((tick-tick_tarea1)>=TICKS_PER_SECOND/10)//aprox 100ms
      {
         tick_tarea1=tick;//actualiza el los tick de la tarea1
         tarea1();                          //lanza la tarea 1
      }
      if((tick-tick_tarea2)>=TICKS_PER_SECOND/3.3)//aprox 300ms
      {
         tick_tarea2=tick; //actualiza el los tick de la tarea2
         tarea2();                           //lanza la tarea 2
      }
      if((tick-tick_tarea3)>=TICKS_PER_SECOND)       //aprox 1s
      {
         tick_tarea3=tick; //actualiza el los tick de la tarea3
         tarea3();                           //lanza la tarea 3
      }
   }
}
/*****************************************************************************/
esquema.png
 

Adjuntos

Última edición:
#2
Hay un problema: cuando el temporizador de 16 bits desborda, el valor de get_ticks() vuelve a 0.

Como las variables tick_tarea* siempre crecen, eso quiere que los if() que comprueban si se ha superado el lapso de tiempo por tarea dejarán de cumplirse, por lo que el sistema dejará de funcionar al cabo de 10 minutos, 55 segundos, y 36 centésimas.

La solución es poner un control más, para comprobar si get_ticks() ha vuelto a cero, y en ese caso, poner a cero las variables tick_tarea*, antes de las comprobaciones.

Por ejemplo (no probado):
C:
    unsigned int16 tick,ant_tick,tick_tarea1=0,tick_tarea2=0,tick_tarea3=0;

    // hemos añadido una variable ant_tick para llevar el control de desborde

    while(true) {                          // bucle infinito

        tick = get_ticks();                 // lee el valor actual de los ticks

        if (tick < ant_tick) {                // caso de desborde
            // colocamos lapsos al principio de la cuenta
            if (tick < tick_tarea1)
                tick_tarea1 = 65535 - tick_tarea1;
           
            if (tick < tick_tarea2)
                tick_tarea2 = 65535 - tick_tarea2;

            if (tick < tick_tarea3)
                tick_tarea3 = 65535 - tick_tarea3;
        }

        // ... resto de líneas
       
        // ... al final del bucle while(), añadimos
        ant_tick = tick;
    }
Atención: NO vale con poner las variables a 0 cuando se detecta un desborde: hay que respetar la posición de lapso de tiempo en que se encuentra cada una.

Atención 2: con un par de trucos, nos podemos ahorrar la variable ant_tick.
 
Última edición:
#3
Hay un problema: cuando el temporizador de 16 bits desborda, el valor de get_ticks() vuelve a 0.
Ese fue el primer detalle que tuve que reflexionar cuando vi este método en el ejemplo de CCS picC.
Como las variables tick_tarea* siempre crecen, eso quiere que los if() que comprueban si se ha superado el lapso de tiempo por tarea dejarán de cumplirse, por lo que el sistema dejará de funcionar al cabo de 10 minutos, 55 segundos, y 36 centésimas.
En realidad no, debido a que:

Por ejemplo.

Si la diferencia entre los ticks fuese 6 y se llegara al siguiente caso (asumiremos un tamaño de 8 bits sin signo... ya que es más fácil asi).

Tick actual=253
Tick anterior=247

253-247=6 -> 0xFD-0xF7=0x06

Si expresamos esta operación en binario.

0xFD -> 11111101
0xF7 -> 11110111

Tenemos: 11111101-11110111

Una resta puede hacerse mediante una suma con complemento a 2.

El complemento a 2 de 11110111->00001001

11111101-11110111=11111101+00001001...como se trata de un entero sin signo de 8 bits el valor final del resultado también es sinsigno de 8 bits y el acarreo que pudiera existir no se toma en cuenta.
Código:
                   11111101
                  +
                   00001001
                  ---------
        Acarreo->1|00000110->0x06
En este caso la diferencia es correcta tick actual>tick anterior.

Cuando ocurre el desborde por ejemplo de 0xFD a 0x03.

tick actual=0x03
tick anterior=0xFD

0x03-0xFD->00000011-11111101

Igual que en el anterior caso la resta mediante complemento a 2 se hace suma.

Complemento a 2 de 11111101->00000011
Código:
                   00000011
                  +
                   00000011
                  ---------
        Acarreo->0|00000110->0x06
En ambos casos la diferencia como entero sin signo de 8 bits es de 6 por tanto no importa si ocurre el desborde, el programa sigue funcionando sin fallar.

Dentro de poco subiré algún ejemplo más interesante que el parpadeo de leds.
Un saludo y hasta la próxima vez.

Solo para verificar la hipótesis deje en simulación el circuito con el programa y después de 27 minutos el programa sigue funcionado, sé que una simulación no es lo mismo que el circuito real, pero en este caso considero que puedo confiar en la simulación.

De todos modos en el parámetro tick de #use timer se pueden elegir tamaños de 8,16 y 32 bits.
 
Última edición:
#4
Otro detalle es que las tareas no se programan "libremente", dentro de una tarea no pueden haber delays ni bucles cerrados esperando a que pase algo.
Por ejemplo, no puede haber un bucle que se quede esperando a que se pulse una tecla, por decir algo.
 
#5
Solo para verificar la hipótesis deje en simulación el circuito con el programa y después de 27 minutos el programa sigue funcionado, sé que una simulación no es lo mismo que el circuito real, pero en este caso considero que puedo confiar en la simulación.

De todos modos en el parámetro tick de #use timer se pueden elegir tamaños de 8,16 y 32 bits.
Gracias por la aclaración. De todos modos, no queda indicado en el código, y queda al criterio del compilador decir que la diferencia de enteros sin signo debe ser así para usarse con la expresión de la derecha. Humm... mejor poner algún cast, por si acaso.
 
#6
Otro detalle es que las tareas no se programan "libremente", dentro de una tarea no pueden haber delays ni bucles cerrados esperando a que pase algo.
Por ejemplo, no puede haber un bucle que se quede esperando a que se pulse una tecla, por decir algo.
Es cierto, dentro de un sistema multare no caben los delays y los bucles que esperan algún evento, por lo menos no intencionalmente. Seguramente cuando se usan algunas librerías probablemente estas tengan en su código algún delay pequeñísimo, de buena fe esperamos que esas librerías no desestabilicen al sistema.

Por lo menos el objetivo de lo que voy a ir subiendo es no tener ningún delay mas dentro del código que efectuemos.
... mejor poner algún cast, por si acaso.
Eso sí, a nadie le hace daño un cast.
 
#7
Hace poco utilice el timer por primera vez, en un programa para contar objetos con Displays de leds. Use la interrupción por RB0 (gracias a D@rkbytes) debía hacer un delay para evitar el rebote al contar y use el timer0 para eso. Todo funciono muy bien, pero hasta ahora no se que tiempo esta haciendo el timer ni como aumentarlo; simplemente use todo el rango (0 - 255 con el máximo prescaler y bandera de overflow). Seria bueno que explicaran como configurar el timer (leí algo pero no me queda claro) para contar el tiempo que uno necesite. Es un tema muy interesante. Gracias.
 

Dr. Zoidberg

Well-known-Papá Pitufo
#8
Me gusta la idea...pero yo lo escribiría de otra forma por que si nó, el codigo de despacho se enrieda muy rápidamente. Yo hice algo muy parecido a esto hace mas de 20 años pero con el timer de la PC. Si algun dia encuentro los diskettes donde lo tenía, prometo subirlo.

Ahí vá... lo escribí en 10 minutos y no lo revisé mucho, pero creo que se entiende el mecanismo de despacho (que es el mismo publicado mas arriba) pero con algunos cambios menores para explotar un poco la potencia expresiva del lenguaje C.

C:
typedef struct {
    void (*ftarea)();
    int16 ticks;
    int16 tickCnt;
} TAREA;

void disparaTareas( TAREA tareas[], int tcant ) {
int16 i, tk;

while( true ) {
    tk = get_ticks();
    for( i = 0; i < tcant; i++ ) {
        if( ( tk-tareas[i].ticksCnt ) >= tareas[i].ticks ) {
            tareas[i].tickCnt = tk;
            tareas[i].ftarea();
        }
    }
}

}

/*---------------------
Aca ponen las funciones de cada tarea
igual que en el primer ejemplo
--------------------*/

void main() {

TAREA tareas[ ] = {
        { tarea1, 10, 0 },
        { tarea2, 30, 0 },
        { tarea3, 100, 0 }
        };

disparaTareas( tareas, 3 );

}
De mas esta decir que se admiten criticas, cambios y mejoras.

PD: Se me ocurre que se podría leer el contador de ticks dentro del for y no dentro del while....pero hay que analizarlo.

PD2: Tal como comenta Scooter, esto es multitarea cooperativo, así que hay que agregar una pequeña API para cosas tales como liberar el control de la CPU en un loop "ciego" y ese tipo de cosas. No es gran trabajo pero hay que hacerlo.
 
Última edición:
#9
Como complemento a este artículo estaría bien crear otro explicando el modo RTOS (Real Time Operating System) del CCS (multitarea cooperativa).

En el manual está a partir de la página 94.

En principio, lo que hacen las funciones rtos_* es "esconder" buena parte de la infraestructura necesaria que Saint_ nos ha mostrado con #use timer.
 
#10
Buenas noches, aunque para mí son buenas madrugadas (01:45 en este instante).

Me simpatiza mucho el modo que Dr. Zoidberg propone para el despacho de las tareas, lo lamentable es que CCS PicC no soporta punteros a funciones así que no podríamos ir por ese lado. En cambio si se podría aplicar para implementar pseudo objetos y asi poder manejar de 1 a N motores pap por ejemplo o más de un LCD alfanumérico sin necesidad de estar creando nuevas librerías para cada caso.

Seria bueno que explicaran como configurar el timer (leí algo pero no me queda claro) para contar el tiempo que uno necesite. Es un tema muy interesante. Gracias.
habria que crear un post donde se explique a detalle las interrupciones y su modo de uso segun el compilador que se use.

Como complemento a este artículo estaría bien crear otro explicando el modo RTOS (Real Time Operating System) del CCS (multitarea cooperativa).
Me parece una Genial idea. Después que termine estas entregas y si nadie más se anima entonces subiria unos artículos sobre el Rtos de CCS.

Mientras tanto:
Este el segundo ejemplo sobre esta metologia para multiatrea en CCS.
Para este ejemplo tendremos:

Se tendrán 4 displays de 7 segmentos, dos de los cuales serán un contador ascendente descendente según la posición de un switch.

Los restantes displays serán un contador de pulsos provenientes de un pulsador.

Se tendrá un motor paso a paso girando a razón de 50ms por paso y un led que parpadea a razón de 500ms.

Para el manejo de los displays se usara el método de multiplexacion, podría usarse latchs pero la idea es tener la menor cantidad de hardware posible usando como base al pic16f628A.

Dividiremos el programa en 5 tareas.

Tarea 1, mantener girando el motor paso a paso

Tarea 2, mantener parpadeando al led.

Tarea 3, lectura del pulsador.

Tarea 4, multiplexar al 4 displays.

Tarea 5, lectura del estado del switch.

Se colocara en el puerto A al motor paso a paso, al led, al pulsador y al switch. Como en este puerto existen pines de entrada y otros de salida usaremos la directiva #USE FIXED_IO para no tener problemas.

La forma de enviar información de una tarea a otra tarea será mediante variables globales.

En el archivo .h
C:
/*****************************************************************************/
#include <16F628A.h>
/*****************************************************************************/
#FUSES NOWDT
#FUSES PUT                      //Power Up Timer
#FUSES MCLR                     //Master Clear pin enabled
#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 NOPROTECT                //Code not protected from reading
/*****************************************************************************/
#use delay(internal=4MHz)
/*****************************************************************************/
#USE TIMER(TIMER=1,TICK=1ms,BITS=16,NOISR)
/*****************************************************************************/
#use fixed_io(a_outputs=PIN_A0,PIN_A1,PIN_A2,PIN_A3,PIN_A7)
#use fixed_io(b_outputs=PIN_B0,PIN_B1,PIN_B2,PIN_B3,PIN_B4,PIN_B5,PIN_B6, PIN_B7)
/*****************************************************************************/
unsigned int8 pulsos=0;//contador de pulsos
unsigned int8 cuenta=0;//contador de cuenta
/*****************************************************************************/
En el archivo .c
C:
#include <main.h>
/*****************************************************************************/
void tareaContador()
{
   if(input(pin_a6))    //si es 1 cuenta ascendente
   {
      if(++cuenta==100) //si llega a 100
      {
         cuenta=0;
      }
   }
   else                 //si es 0 cuenta descendente
   {
      if(--cuenta==255) //si se desborda
      {
         cuenta=99;
      }
   }
}
/*****************************************************************************/
void tareaPulsador()
{
   static unsigned int8 pulsadorEstadoAnterior=1;
   unsigned int8 pulsadorEstadoActual;
   pulsadorEstadoActual=input(pin_a4);
   if((!pulsadorEstadoActual)&&(pulsadorEstadoAnterior))//si existió un cambio
   {                                                     //de estado de 1 a 0
      if(++pulsos==100) //si la cuenta llega a 100
      {
         pulsos=0;
      }
   }
   pulsadorEstadoAnterior=pulsadorEstadoActual;//actualiza el estado del pulsador
}
/*****************************************************************************/
void tareaDisplay()
{
   char disp[5];
   char dispN[]={0xe0,0xd0,0xb0,0x70};
   static unsigned int n;
   sprintf(disp,"%02u%02u",pulsos,cuenta);
   output_b(dispN[n]|(disp[n]&0x0f));
   (++n)&=0x03;
}
/*****************************************************************************/
void tareaLed()
{
   output_toggle(pin_a7);//cambia d estado a led
}
/*****************************************************************************/
void tareaMotor()
{
   char pasos[]={1,2,4,8};//secuencia del motor paso a paso
   char temp;             //variable de uso general
   static char paso;      //contador de pasos
   temp=input_a()&0xf0;//se rescata los 4 bits más significativos del puerto A
   temp|=pasos[paso++];//escribe en los bits menos significativos el paso
                       //correspondiente al motor
   paso&=0x03;         //forza a que no se exceda de paso 3
   output_a(temp);     //escribe en el puerto A
}
/*****************************************************************************/
void main()
{
   unsigned int16 tick,tickTareaMotor=0,tickTareaLed=0;
   unsigned int16 tickTareaDisplay=0,tickTareaPulsador=0,tickTareaContador=0;
 
   while(TRUE)
   {
      tick=get_ticks();
      if((tick-tickTareaMotor)>=TICKS_PER_SECOND/20)//aprox 50ms
      {
         tickTareaMotor=tick;
         tareaMotor();
      }
      if((tick-tickTareaLed)>=TICKS_PER_SECOND/2)//aprox 500ms
      {
         tickTareaLed=tick;
         tareaLed();
      }
      if((tick-tickTareaDisplay)>=TICKS_PER_SECOND/200)//aprox 5ms
      {
         tickTareaDisplay=tick;
         tareaDisplay();
      }
      if((tick-tickTareaPulsador)>=TICKS_PER_SECOND/10)//aprox 100ms
      {
         tickTareaPulsador=tick;
         tareaPulsador();
      }
      if((tick-tickTareaContador)>=TICKS_PER_SECOND/3.3)//aprox 300ms
      {
         tickTareaContador=tick;
         tareaContador();
      }
   }
}
/*****************************************************************************/
esquema.png
 

Adjuntos

Última edición:
#13
La versión en la que estoy escribiendo el código es en 5.07 y en el help menciona:

Attempt to create a pointer to a constant

Constant tables are implemented as functions. Pointers cannot be created to functions. For example CHAR CONST MSG[9]={"HI THERE"}; is permitted, however you cannot use &MSG. You can only reference MSG with subscripts such as MSG and in some function calls such as Printf and STRCPY.



Pero haciendo pruebas, si soporta puntero a función, pero sigue generando error cuando el puntero a función está dentro de una estructura.

Pero la solución esta tal cual lo mencionan en el enlace que recomienda Dr. Zoidberg.

Aqui el mismo ejemplo del primer post pero con la modificacion que Dr. Zoidberg propone, por lo menos ami me gusta mas este nuevo modo.
C:
#include <16f84a.h>
#fuses nowdt,put,noprotect
#use delay(crystal=4M)
#use timer(timer=0,tick=10ms,bits=16,noisr)
/******************************************************************************
Estructura para la creación de tareas (esto no debería cambiarse)
******************************************************************************/
typedef void(*punteroFuncion)(void);
typedef struct {
                  punteroFuncion pf;
                  unsigned int16 periodo;
                  unsigned int16 tickCont;
               }TAREA;
/******************************************************************************
Función despachadora de tareas (esto no debería cambiarse)
******************************************************************************/
void despachadorTareas(TAREA tareas[],unsigned int8 tCant)
{
   unsigned int16 tick;
   unsigned int8 i=0;
   while(true)
   {
      tick=get_ticks();
      for(i=0;i<tCant;i++)
      {
         if((tick-tareas[i].tickCont)>=tareas[i].periodo)
         {
            tareas[i].tickCont=tick;//actualiza los ticks
            tareas[i].pf();                //despacha la tarea correspondiente
         }
      }
   }
}
/*****************************************************************************/
void tarea1()
{
   output_toggle(pin_a0);
}
/*****************************************************************************/
void tarea2()
{
   output_toggle(pin_a1);
}
/*****************************************************************************/
void tarea3()
{
   output_toggle(pin_a2);
}
/*****************************************************************************/
void main()
{ 
   TAREA tareas[]={
                  {tarea1,TICKS_PER_SECOND/10,0}, //crea la tarea1,aprox 100ms,0->la tarea inicia en aprox 100ms
                  {tarea2,TICKS_PER_SECOND/3.3,0},//crea la tarea2,aprox 300ms,0->la tarea inicia en aprox 300ms
                  {tarea3,TICKS_PER_SECOND/1,1}   //crea la tarea3,aprox 1s,1->la tarea inicia inmediatamente
                  };
   despachadorTareas(tareas,3);  //llama al despachador de tareas, 3 es la
                                 //cantidad de tareas creadas
}
/*****************************************************************************/
 

Dr. Zoidberg

Well-known-Papá Pitufo
#14
No se entiende nada lo que quoteste del help...jaja.
O le tradujo un chino trasnochado o el que lo escribio fumaba cosas raras...

PD: no me gusta usar divisiones en punto flotante para un parametro que termina siendo entero.

PD2:fijate de meter la invocacion a get_ticks antes del if para tener un control mas cercano del momento del despacho. No es garantia de nada pero "se me ocurre" que puede ayudar..
 
Última edición:
#15
No se entiende nada lo que quoteste del help...jaja.
O le tradujo un chino trasnochado o el que lo escribio fumaba cosas raras...
Puede ser, pero es copia fiel del lo que esta escrito en el help de CCS.
PD: no me gusta usar divisiones en punto flotante para un parametro que termina siendo entero.
Algún rato ese "mal" es necesario. De todos modos uno siempre es libre de ponerle un valor entero dependiendo de la frecuencia de ejecución de la tarea.
PD2:fijate de meter la invocacion a get_ticks antes del if para tener un control mas cercano del momento del despacho. No es garantia de nada pero "se me ocurre" que puede ayudar..
La diferencia entre get_ticks(); fuera del bucle for o dentro son unos cuantos us no hace alguna diferencia notoria. De todos modos esa sería una opción que el programador podría usar si desearía, en mi caso lo dejaria fuera del for.
 

Dr. Zoidberg

Well-known-Papá Pitufo
#16
La diferencia entre get_ticks(); fuera del bucle for o dentro son unos cuantos us no hace alguna diferencia notoria. De todos modos esa sería una opción que el programador podría usar si desearía, en mi caso lo dejaria fuera del for.
Si seguis de cerca el tiempo de despacho podrias hacer cosas interesantes, tales como medir la desviacion del despacho real de cada tarea respecto al tiempo previsto, y eso podria ayudar a optimizar la secuencia de despacho o el codigo de las tareas.
Por supuesto, hay que armar una API con acceso a los datos de cada tarea y que permita hacer otras cosas interesantes, y todo esto solo vale cuando los intervalos de tiempo son pequeños.
Pero bue....era una idea
 

Dr. Zoidberg

Well-known-Papá Pitufo
#17
Otra cosa que recomiendo hacer es consteuir un archivo .h (ponele... tareas.h) que contenga los typedef y el prototipo del despachador de tareas, y luego un .c (tareas.c) que contenga la definicion del despachador.
De esa manera solo se hace
#include "tareas.h"
En el programa y agregando tareas.c al proyecto se protege el mecanismo de despacho de modificaciones involuntarias..o nó.
 
#18
....
Algún rato ese "mal" es necesario. De todos modos uno siempre es libre de ponerle un valor entero dependiendo de la frecuencia de ejecución de la tarea.
Usar get_ticks() es quizás de las peores elecciones para llevar varios temporizadores. Para eso no solo no hace falta punto flotante, ni siquiera hace falta dividir, solamente restar 1.

Por ejemplo:
- Se crea una interrupción por overflow de un timer y se decrementan contadores (int8 o int16, lo que haga falta)
- Cuando cada contador llega a 0 se recarga y activa un bit de estado.
- En el bucle principal se comparan los bits de estado y cuando se activan, se resetean y llaman a la tarea correspondiente.

Declaro variables
int1 ovfw1=0 , ovfw2=0 , ovfw3=0 ; // Overflows
int8 tmr1=0 , tmr2=0 , tmr3=0 ; // Contadores
int8 tmr1_0 , tmr2_0 , tmr3_0 ; // Valor inicial


En la interrupción
if(--tmr1==0){ tmr1 = tmr1_0 ; ovfw1 = 1 ;} // Tiempo 1
if(--tmr2==0){ tmr2 = tmr2_0 ; ovfw2 = 1 ;} // Tiempo 2
if(--tmr3==0){ tmr3 = tmr3_0 ; ovfw3 = 1 ;} // Tiempo 3


En main
void main(){
....................................
tmr1_0 = 200 ;
tmr2_0 = 300 ;
tmr3_0 = 100 ;
.....................................
while(true){
if(ovfw1){ ovfw1=0 ; tarea1() ;}
if(ovfw2){ ovfw2=0 ; tarea2() ;}
if(ovfw3){ ovfw3=0 ; tarea3() ;}
...................................................
}
.....................................
}
 

Dr. Zoidberg

Well-known-Papá Pitufo
#19
Usar get_ticks() es quizás de las peores elecciones para llevar varios temporizadores
Es que no estas llevando varios temporizadores, sino uno solo sobre el cual se despachan todas las tareas.
Esto no es, ni por cerca, una implementacion hard-real-time pero tampoco lo son los multiples temporizadores, donde el polling de los bits de estado es un equivalente a get_ticks.
Entiendo que este tema pretende proporcionar una metodologia mas o menos simple y estandarizada para sincronizar tareas sobre un timer y asi eliminar los delays....pero puedo estar equivocado.
 
#20
Es decir... que nos debemos ajustar a
  1. las capacidades del propio micro: velocidad, memoria, número de temporizadores libres, su resolución, tiempo de cambio de contexto, etc.
  2. las tareas a realizar: cuántas, cuánto tiempo van a consumir, si son cooperativas o apropiativas, o incluso bloqueantes
  3. la resolución exigida por el cliente: en algunas aplicaciones podemos asumir un fallo de 1 segundo/día (regar las plantas), pero en otros casos, no (regular un parque semafórico, controlar una máquina herramienta)
Particularmente, de lo mostrado hasta ahora, no estoy de acuerdo con lo de los bucles infinitos (#use timer también pueden funcionar en modo ISR), pero es porque siempre intento que el chip consuma lo menos posible.
 

Temas similares


Arriba