Inicio rápido de RT-Thread - Gestión del temporizador

 

1 tictac del reloj

Cualquier sistema operativo debe proporcionar un tic de reloj para que el sistema maneje todos los eventos relacionados con el tiempo, como el retraso, la programación de subprocesos por turnos y el tiempo de espera del temporizador. El tic del reloj (OS Tick) es la unidad de tiempo más pequeña del sistema operativo.

El tic del reloj es una interrupción periódica específica, y el intervalo de tiempo entre las interrupciones depende de la aplicación específica, generalmente de 1 a 100 ms. Cuanto más rápida sea la frecuencia de tictac del reloj, mayor será la sobrecarga del sistema.

En RT-Thread, la duración de un pulso de reloj  RT_TICK_PER_SECOND se ajusta de acuerdo con la definición en el archivo de configuración rtconfig.h, que es igual a  1/RT_TICK_PER_SECOND segundos.

Realización de tictacs de reloj.

El latido del reloj es generado por un temporizador de hardware configurado como un modo de activación de interrupción, y se llama a la siguiente función en la rutina de servicio de interrupción para notificar al sistema operativo que ha pasado un reloj del sistema:

void rt_tick_increase(void)
{
  struct rt_thread *thread;

  /* 全局 rt_tick 递增 */
#ifdef RT_USING_SMP
  rt_cpu_self()->tick ++;
#else
  ++ rt_tick;
#endif

  /* 检查时间片 */
  thread = rt_thread_self();

  -- thread->remaining_tick;
  if (thread->remaining_tick == 0)
  {
    /* 重新赋初值 */
    thread->remaining_tick = thread->init_tick;
    /* 线程挂起 */
    thread->stat |= RT_THREAD_STAT_YIELD;

    /* yield */
    rt_thread_yield();
  }

  /* 检查定时器 */
  rt_timer_check();
}

Se puede ver en el código fuente que  rt_tick el valor de la variable global aumentará en 1 cada vez que pase un tic del reloj. A continuación, compruebe si se ha agotado el intervalo de tiempo del subproceso actual y si se ha agotado el tiempo de espera de un temporizador. Si se agota el intervalo de tiempo del subproceso actual, cambie entre subprocesos de la misma prioridad.

Las diferentes implementaciones de interrupción del temporizador de hardware son diferentes.Tome la interrupción del temporizador STM32 como ejemplo:

void SysTick_Handler(void)
{
  /* 进 入 中 断 */
  rt_interrupt_enter();
  ……
  rt_tick_increase();
  /* 退 出 中 断 */
  rt_interrupt_leave();
}

En la función de interrupción, la llamada   suma 1 rt_tick_increase() a la variable global  .rt_tcik

rt_tick El valor de representa el número de pulsos de reloj que ha pasado el sistema desde que se inició.

2 mecanismo de trabajo del temporizador

El temporizador proporcionado por RT-Thread se basa en el tiempo del sistema y proporciona la capacidad de tiempo en función del múltiplo entero del tiempo, es decir, el tiempo del temporizador se basa en el tic del reloj. De esta forma, la duración del tiempo del temporizador es  OS Tick un múltiplo entero de la duración.

Si un latido del reloj es de 10 ms, la duración del temporizador del software del sistema solo puede ser de 10 ms, 20 ms, 100, etc., no de 15 ms.

Introducción al temporizador

RT-Thread proporciona dos tipos de temporizadores:

  • Temporizador de un disparo. Este tipo de temporizador se detendrá automáticamente después de que se active un evento de temporizador.

  • Temporizador de disparo periódico. Este tipo de temporizador activa eventos de temporizador periódicamente hasta que el usuario los detiene manualmente.

Además, según el contexto en el que se ejecute la función de tiempo de espera, el temporizador RT-Thread tiene dos modos de funcionamiento:

  • HARD_TIMER modo, la función de tiempo de espera se ejecuta en el contexto de interrupción.

  • SOFT_TIMER  Modo, ejecutado en el entorno de contexto del subproceso del temporizador creado por el sistema.

HARD_TIMER temporizador de modo

Este modo es el modo de trabajo predeterminado del temporizador RT-Thread.Después de que el temporizador expira, la función de tiempo de espera se ejecuta en el contexto de la interrupción del reloj del sistema.

En este caso, los requisitos para la función de tiempo de espera son los mismos que para la rutina de servicio de interrupción: el tiempo de ejecución debe ser lo más breve posible y la ejecución no debe provocar que el subproceso actual se cuelgue, etc. De lo contrario, se alargará el tiempo de respuesta de otras interrupciones o se adelantará el tiempo de ejecución de otros subprocesos.

SOFT_TIMER temporizador de modo

Este modo de trabajo debe  RT_USING_TIMER_SOFT habilitarse mediante definición de macro. Después de habilitar este modo, RT-Thread creará un subproceso de temporizador durante la inicialización, y las SOFT_TIMER funciones de tiempo de espera del temporizador del modo se ejecutarán en el subproceso de temporizador.

Cómo funcionan los temporizadores

RT-Thread mantiene dos variables globales importantes:

  • rt_tick , el número de tics de reloj pasados ​​por el sistema actual.

  • rt_timer_list , una lista enlazada de temporizadores. Los temporizadores creados y activados se ordenarán de acuerdo con el tiempo de espera de menor a mayor y se insertarán en esta lista vinculada.

Como se muestra en la siguiente figura, el valor actual de rt_tick del sistema es 20, y se han creado e iniciado tres temporizadores: (1) Timer1 con un tiempo de 50 latidos (2) timer2 con un tiempo de 100 latidos (3) a temporizador de 500 latidos beat timer3.

Estos tres temporizadores se agregan a la hora actual del sistema respectivamente  rt_tick, y los enlaces se ordenan de menor a mayor  rt_timer_list :

imagen

 

rt_tick A medida que aumenta la activación del temporizador de hardware, después de 50 latidos, aumentará rt_tick de 20 a 70, que  timerout es el mismo valor del temporizador 1. En este momento, se activará la función de tiempo de espera asociada con el temporizador Timer1, y se eliminará  rt_timer_list de la lista vinculada al mismo tiempo.

De manera similar, después de que hayan transcurrido 100 latidos y 500 latidos, las funciones de tiempo de espera de los temporizadores Timer2 y Timer3 se activarán para ejecutarse, y los temporizadores Timer2 y Timer3 rt_timer_list se eliminarán

Bloque de control del temporizador

struct rt_timer El bloque de control del temporizador es una estructura de datos utilizada por RT-Thread para administrar el temporizador.El objeto del kernel del temporizador está definido por la estructura  y luego se vincula al contenedor del kernel para su administración.

El bloque de control del temporizador almacenará cierta información del temporizador, como la cantidad de latidos iniciales del reloj, la cantidad de latidos alcanzados por el tiempo de espera, la estructura de la lista vinculada utilizada para la conexión entre los temporizadores y la función de devolución de llamada de tiempo de espera. La definición específica es la siguiente:

struct rt_timer
{
  struct rt_object parent;
  rt_list_t row[RT_TIMER_SKIP_LIST_LEVEL]; /* 定时器链表节点 */
  
  void (*timeout_func)(void *parameter);  /* 定时器超时函数 */
  void *parameter;                        /* 超时函数的参数 */
  
  rt_tick_t init_tick;     /* 定时器设定的超时节拍数 */
  rt_tick_t timeout_tick;  /* 定时器实际超时时的节拍数 */
};
typedef struct rt_timer *rt_timer_t;

Gestión de 3 temporizadores

El conocimiento teórico relacionado con los temporizadores se introdujo anteriormente, entonces, ¿qué tipo de funciones de operación del temporizador proporciona RT-Thread y cómo usarlas?

Las operaciones relacionadas con el temporizador proporcionadas por RT-Thread incluyen:

  • Crear/Inicializar temporizador

  • temporizador de inicio

  • temporizador de control

  • Temporizador de eliminación/desactivación

Todos los temporizadores se eliminarán de la lista de enlaces de temporizadores después de que expire el tiempo, y el temporizador periódico se agregará a la lista de enlaces de temporizadores cuando comience de nuevo.

imagen

 

1. Crea un temporizador

Hay dos formas de crear un temporizador: creación dinámica e inicialización estática.

Para crear dinámicamente un temporizador , use la siguiente interfaz de función:

rt_timer_t rt_timer_create(const char *name,
                           void (*timeout)(void *parameter),
                           void       *parameter,
                           rt_tick_t   time,
                           rt_uint8_t  flag)

Después de llamar a esta función, el núcleo asigna automáticamente un bloque de control de temporizador del montón de memoria y luego inicializa el bloque de control de temporizador. Cada parámetro se describe de la siguiente manera:

parámetro describir
nombre nombre del temporizador
se acabó el tiempo Puntero de función de tiempo de espera del temporizador
parámetro El parámetro de entrada de la función de tiempo de espera del temporizador
tiempo El tiempo de espera del temporizador, la unidad es el latido del reloj
bandera Los parámetros para crear un temporizador, sus valores incluyen temporización única, temporización periódica, temporizador de hardware, temporizador de software, etc.

No se pudo crear, devuelva RT_NULL. Si la creación tiene éxito, se devolverá el puntero del bloque de control del temporizador.

La definición de macro utilizada por la bandera del temporizador:

#define RT_TIMER_FLAG_ONE_SHOT 0x0    /* 单 次 定 时 */
#define RT_TIMER_FLAG_PERIODIC 0x2    /* 周 期 定 时 */

#define RT_TIMER_FLAG_HARD_TIMER 0x0  /* 硬 件 定 时 器 */
#define RT_TIMER_FLAG_SOFT_TIMER 0x4  /* 软 件 定 时 器 */

Los dos grupos anteriores se pueden asignar de forma lógica "o"  flag.

La creación estática de un temporizador requiere que el usuario defina una  struct rt_timer variable de estructura de bloque de control del temporizador, y luego  rt_timer_init() la función la inicializa. El prototipo de la función es el siguiente:

void rt_timer_init(rt_timer_t timer,
                  const char *name,
                  void   (*timeout)(void* parameter),
                  void   *parameter,
                  rt_tick_t time, rt_uint8_t flag);

Esta función  rt_timer_create() tiene un parámetro más  timery los otros parámetros son iguales, así que no los repetiré aquí. El parámetro  timer es en realidad un puntero de bloque de control de temporizador.

2. Inicie el temporizador

Después de crear el temporizador, no se iniciará inmediatamente y debe comenzar a funcionar después de llamar a la interfaz de la función de inicio del temporizador.

La función de temporizador de inicio proporcionada por RT-Thread es la siguiente:

rt_err_t rt_timer_start(rt_timer_t timer);

El parámetro de la función  timer es el puntero del bloque de control del temporizador (manecilla del temporizador), que apunta al bloque de control del temporizador que se iniciará.

Después de llamar a la función de inicio, el estado del temporizador cambia al estado activo y se inserta en la  rt_timer_list lista de la cola en el orden del tiempo de espera.

Después de iniciar el temporizador, si desea detenerlo, puede usar la siguiente función:

rt_err_t rt_timer_stop(rt_timer_t timer);

Después de llamar a esta función, el estado del temporizador cambia a detenido,  rt_timer_list se separa de la lista vinculada y no participa en la verificación del tiempo de espera del temporizador.

La función devuelve RT_EOK, lo que indica que el temporizador se detuvo correctamente. Devuelve -RT_ERROR, lo que indica que el temporizador se ha detenido.

Demostración de aplicación de 4 temporizadores

Teoría + práctica es la forma más efectiva de aprender nuevos conocimientos.

Ejemplo para demostrar cómo crear un temporizador. Esta rutina crea dinámicamente dos temporizadores, un temporizador de un solo uso y un temporizador periódico, y detiene el temporizador después de ejecutarse durante un período de tiempo. el código se muestra a continuación:

#include <rtthread.h>

/* 定时器的控制块 */
static rt_timer_t timer1;
static rt_timer_t timer2;
static int cnt = 0;

/* 定时器1超时函数 */
static void timeout1(void *parameter)
{
 rt_kprintf("periodic timer is timeout %d\n", cnt);
 /* 运行第 10 次,停止周期定时器 */
 if (cnt++>= 9)
 {
  rt_timer_stop(timer1);
  rt_kprintf("periodic timer was stopped! \n");
 }
}
/* 定时器 2 超时函数 */
static void timeout2(void *parameter)
{
 rt_kprintf("one shot timer is timeout\n");
}

int main()
{
 /* 创建定时器1周期定时器 */
 timer1 = rt_timer_create("timer1", timeout1,
                RT_NULL, 10,
                RT_TIMER_FLAG_PERIODIC);
 /* 启动定时器1 */
 if (timer1 != RT_NULL) 
 {
  rt_timer_start(timer1);
 }
 
 /* 创建定时器2单次定时器 */
 timer2 = rt_timer_create("timer2", timeout2,
                RT_NULL, 30,
                RT_TIMER_FLAG_ONE_SHOT);
 /* 启动定时器2 */
 if (timer2 != RT_NULL) 
 {
  rt_timer_start(timer2);
 }
 
 return 0;
}

Los resultados de compilación y ejecución son los siguientes:

imagen

 

La función de tiempo de espera del temporizador periódico 1 se ejecuta una vez cada 10 latidos, se ejecuta 10 veces en total y luego se detiene (llama a  rt_timer_stop()).

La función de tiempo de espera del temporizador de disparo único 2 se ejecuta una vez después de 30 tics.

El siguiente ejemplo ilustra la creación estática de un temporizador.Es necesario definir la variable de la estructura del bloque de control del temporizador y luego llamar a la función de inicialización para inicializarlo:

#include <rtthread.h>

/* 定时器的控制块 */
static struct rt_timer timer1;
static struct rt_timer timer2;
static int cnt = 0;

/* 定时器1超时函数 */
static void timeout1(void* parameter)
{
  rt_kprintf("periodic timer is timeout\n");
  /* 运行10次 */
  if (cnt++>= 9)
  {
   rt_timer_stop(&timer1);
  }
}
/* 定 时 器 2 超 时 函 数 */
static void timeout2(void* parameter)
{
 rt_kprintf("one shot timer is timeout\n");
}

int main(void)
{
  /* 初始化定时器1 */
  rt_timer_init(&timer1, "timer1", /* 定 时 器 名 字 是 timer1 */
              timeout1, RT_NULL, 10, 
              RT_TIMER_FLAG_PERIODIC); /* 周期定时器 */
 /* 初始化定时器2 */
  rt_timer_init(&timer2, "timer2", /* 定 时 器 名 字 是 timer2 */
              timeout2, RT_NULL, 30,
              RT_TIMER_FLAG_ONE_SHOT); /* 单次定时器 */

/* 启动定时器 */
  rt_timer_start(&timer1);
  rt_timer_start(&timer2);

 return 0;
}

Su resultado de ejecución es el mismo que el ejemplo creado dinámicamente.

5 Otras funciones de gestión del temporizador

Los principiantes solo necesitan dominar la creación y el uso de temporizadores. RT-Thread también proporciona otras funciones de gestión de temporizadores para el aprendizaje.

1. Eliminar temporizador

Un temporizador creado dinámicamente se puede eliminar con la siguiente función:

rt_err_t rt_timer_delete(rt_timer_t timer);

Después de llamar a esta interfaz de función, el sistema eliminará este temporizador de la lista vinculada rt_timer_list y luego liberará la memoria ocupada por el bloque de control del temporizador correspondiente.

El temporizador creado estáticamente se puede separar del temporizador con la siguiente función:

rt_err_t rt_timer_detach(rt_timer_t timer);  

Al desconectarse del temporizador, el sistema desconectará el objeto del temporizador del contenedor del objeto del núcleo, pero la memoria ocupada por el objeto del temporizador no se liberará.

2. Temporizador de control

RT-Thread también proporciona una interfaz de función de control de temporizador adicional para obtener o configurar más información del temporizador. La interfaz de la función del temporizador de control es la siguiente:

rt_err_t rt_timer_control(rt_timer_t timer, rt_uint8_t cmd, void* arg);

La interfaz de la función del temporizador de control puede ver o cambiar la configuración del temporizador de acuerdo con los parámetros del tipo de comando.

El parámetro  cmd es el comando que se usa para controlar el temporizador. Actualmente, se admiten cuatro comandos: configurar el tiempo de sincronización, ver el tiempo de sincronización, configurar un disparador único y configurar un disparador periódico.

#define RT_TIMER_CTRL_SET_TIME      0x0  /* 设置定时器超时时间 */
#define RT_TIMER_CTRL_GET_TIME      0x1  /* 获得定时器超时时间 */
#define RT_TIMER_CTRL_SET_ONESHOT   0x2  /* 设置定时器为单次定时器 */
#define RT_TIMER_CTRL_SET_PERIODIC  0x3  /* 设置定时器为周期型定时器 */

arg parámetro para el comando de control.

OK, ven aquí primero hoy, vamos ~

Acho que você gosta

Origin blog.csdn.net/weixin_41114301/article/details/131876644
Recomendado
Clasificación