no veo diferencias entre usar un SO o usar las librerías del lenguaje que estés utilizando en cada momento.
No me cabe duda que un SO tendrá muchas más aportaciones que las librerías, ¿pero cuál es la principal ventaja que los diferencia?
Un SO nos puede ayudar a hacer sistemas más estables.
...
1 ) Intercambio de tareas.
2 ) Prioridad de las tareas.
El intercambio de tareas, es simplemente el guardar el estado de una tarea cuando
ha agotado su tiempo (sus quantums asignados), recuperar el estado de otra tarea
y cederle el control. Normalmente esto se puede realizar por el hardware de la CPU
(existe una instrucción especifica para ello, en "todas" las CPUs del mercado, incluidos
los mainframes). Pero Microsoft en vez de utilizar el mecanismo hardware,
lo hace por software, "a mano". Esto es muy costoso en ciclos de reloj, pero aparentemente,
Microsoft no se fiaba, al menos al principio, de la implementación de
este mecanismo en la CPU por parte de Intel.
Prioridad de las tareas, es simplemente un numero asignado a cada tarea, que indica
el numero de "quantums" que puede ejecutar antes de que el sistema operativo
tome control y le ceda el control a otra tarea.
Hay que hacer notar, que una tarea, puede "perder" el control, antes de agotar su
numero de quantums. Sí esa tarea hace una petición de entrada / salida a disco por
ejemplo, debido a que esa petición es muy costosa en tiempo (estamos hablando
de algunos milisegundos), mientras se ejecuta, evidentemente la CPU puede hacer
muchísimas mas cosas. Por tanto el sistema operativo toma el control y se lo cede
a otra tarea.
El sistema operativo, debe ser "listo". Debe jugar con las prioridades de tarea y variarlas
ligeramente. Es decir, a un programa que hace muchas entradas/salida, debido
a que está poco tiempo en memoria, el sistema operativo le debería subir la
prioridad. En cambio al revés, a un programa que chupa mucha CPU y no realiza
apenas entrada / salida, el sistema operativo debe bajarle la prioridad al objeto de
que no se apodere todo el tiempo de la CPU.
...
Un saludo y espero que lo disfruten.Yo estoy disfrutando sólo con la lectura de tus artículos. Espero gozar probando los RTOS cuando acabe este cursillo, siempre que haya finalizado mi proyecto actual.
Sin embargo quisiera que alguien me dijera donde consigo una versión del compilador GCC para PIC's, si es que existe.
El próximo tema será: El problema del productor-consumidor, uno de los más famosos problemas tipo de la programación con SO.
Yo he trabajado con el CMX-SCHEDULER para el C30 de microchip, es para dsPIC y va genial, es gratuito pero solo puedes priorizar 4 tareas, por las casi 200 que se pueden usar en los de pago.
Estoy intentando crear un RTOS para dsPIC en C30, si os apuntais alguno mas a ayudarme a realizarlo podemos abrir un post e ir posteando ideas y código para realizarlo entre todos, es una buena forma de aprender a fondo las bases de un RTOS.
Muy bueno todo este tema, ya voy a hacer algun proyectito que lo implemente. Pero tengo una duda... no hay algun RTOS o alguna funcionalidad que pueda traer procesos desde una memoria externa, en lugar de tener q declarar funciones que seran los procesos? (como lo hacen nuestras computadoras)
Saludos!
Muy bueno todo este tema, ya voy a hacer algun proyectito que lo implemente. Pero tengo una duda... no hay algun RTOS o alguna funcionalidad que pueda traer procesos desde una memoria externa, en lugar de tener q declarar funciones que seran los procesos? (como lo hacen nuestras computadoras)
Saludos!
Hola mundo con RTOS
Después de teorizar un poco sobre los Sistemas Operativos, vamos a introducirnos en la programación de aplicaciones empleando un RTOS.
En nuestro caso, para comenzar, utilizaremos el RTOS que viene con el compilador de CCS. Las razones de mi elección las expongo a continuación:
- Sencillez en la implementación de aplicaciones
- El RTOS está integrado en el propio compilador de CCS
- Abundante experiencia en el foro con este compilador
- Gran cantidad de dispositivos soportados por el compilador de CCS
Introducción al RTOS de CCS
La versión del compilador que tengo instalada en estos momentos es la 3.249, así que si en versiones posteriores han aparecido nuevas características, les ruego que lo informen para tomar las debidas providencias en el momento oportuno, y comenzar a utilizar esas nuevas características.
El RTOS de CCS es un Sistema Operativo de Tiempo Real que implementa la técnica de multiprocesamiento cooperativo (non preemptive), por lo que es responsabilidad del programador asegurarse de que el control del procesador retorna al planificador de tareas en algún momento. Así que cuando programemos nuestra aplicación, tenemos que asegurarnos de que no llamamos a una función que se queda esperando por algún evento largo como es el caso de gets(), o dentro de un lazo infinito o demasiado extenso.
Planificador de tareas
Uno de los elementos fundamentales de cualquier SO es el planificador de tareas, éste señor es el administrador de nuestros recursos. Su misión fundamental es determinar dentro de las tareas que están listas para ejecutarse, a cuál de ellas le entrega el procesador. La política de planificación empleada por CCS no la conozco, pero eso no importa porque el RTOS funciona y para lo que queremos hacer, nos sirve bien.
Directivas del preprocesador
Existen dos directivas del preprocesador para el uso del RTOS, ellas son:
- #USE RTOS: Se utiliza para indicarle al compilador que se va a utilizar el RTOS
- #TASK: Se utiliza para indicarle al compilador se la función definida a continuación es una tarea a ejecutar por el RTOS
Vamos a ver más detenidamente cada una de las directivas, así como sus parámetros de configuración:
#USE RTOS
Opciones del RTOS:
timer: especifica que temporizador, de los disponibles, es el que se utilizará para la ejecución de las tareas. Este temporizador solamente debe ser utilizado por el RTOS y típicamente se escoge Timer0
minor_cycle: especifica la cantidad de tiempo mínima que una tarea tendrá para ejecutarse, y los tiempos de ejecución de cada tarea deben ser múltiplos de esta cantidad. Si por ejemplo decimos que el tiempo mínimo de ejecución para todas las tareas es de 1ms, debemos conocer que cada tarea se ejecutará, en menos tiempo que este. Lo realmente importante de este dato es que ayuda a establecer la frecuencia con que se ejecutan las tareas, luego veremos un ejemplo de esto. Este parámetro, si no se especifica, es calculado por el compliador en el momento de la compilación.
statistics: le indica al compilador que lleve las estadísticas de las tareas, esto sirve para conocer que tiempo consume cada tarea en ejecutarse, sin embargo como veremos más adelante, la estadística realmente importante es la que nos indica si nuestra tarea se ha sobrepasado en su tiempo mínimo de ejecución.
#TASK
Opciones para las tareas:
rate: especifica con que frecuencia se ejecuta la tarea, este parámetro debe ser igual a minor_cycle de #use_rtos o un múltiplo de este valor.
max: especifica que cantidad de tiempo debe consumir esta tarea en su ejecución, si se sobrepasa este tiempo y están activadas las estadísticas, entonces esta tarea es marcada con el valor overrun. Este parámetro es útil para informar al programador que una tarea se ha pasado de su tiempo de ejecución, y si el RTOS fuera de tiempo compartido seguramente especificaría el tiempo en que el planificador le retira el procesador para dárselo a otra tarea.
queue: especifica el tamaño de la cola de mensajes de la tarea. Si la tarea no recibe mensajes, entonces debe dejarse en blanco para no consumir memoria RAM innecesariamente.
Hasta aquí hemos visto una pequeña explicación de las directivas para utilizar el RTOS. Sin embargo, la utilidad de esto es mejor verla con un ejemplo.
Funciones del RTOS
EL RTOS de CCS ofrece un conjunto de funciones que veremos cada una en su momento y con sus debidos ejemplos. Sin embargo hoy utilizaremos solamente la función rtos_run(), que le indica al planificador que comience a ejecutar las tareas.
El ejemplo
Se quiere implementar una aplicación en un PIC16F877, donde se utilice el RTOS para transmitir por el puerto serie de este uC, tres cadenas de caracteres. Cada cadena será transmitida desde dentro de una tarea del RTOS y tendrán el formato “Ejecutada tarea #”. Las especificaciones de tiempo del sistema y de cada tarea son las siguientes:
- Temporizador para el RTOS: Timer0
- Tiempo mínimo en que debe ejecutarse una tarea: 10ms
- Frecuencia de ejecución de la Tarea 1: 1seg, tiempo para ejecutar: 10ms
- Frecuencia de ejecución de la Tarea 2: 2seg, tiempo para ejecutar: 5ms
- Frecuencia de ejecución de la Tarea 3: 3seg, tiempo para ejecutar: 250us
El código lo pongo a continuación y posteriormente les doy una explicación:Código: C++
#include "D:\Documentos\Projects\RTOS\RTOS.h" #use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=9) #use RTOS(timer=0, minor_cycle=10ms) //temporizador Timer0, tiempo mínimo de ejecución de cada tarea 10ms int8 test; //Definición de las prototipos de función de las tareas #task (rate=1s, max=10ms) //Ejecutar cada 1 segundo y consumir como máximo 10ms void Tarea1(); #task (rate=2s, max=5ms) //Ejecutar cada 2 segundos y consumir como máximo 5ms void Tarea2(); #task (rate=3s, max=250us) //Ejecutar cada 3 segundo y consumir como máximo 250us void Tarea3(); void main() { setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1); rtos_run(); //A partir de aquí comenzará la ejecución de las tareas } //Implementación de las tareas void Tarea1() { printf("Ejecutada tarea 1\r"); } void Tarea2() { printf("Ejecutada tarea 2\r"); } void Tarea3() { printf("Ejecutada tarea 3\r"); }
Este código funciona y si lo simulan con el Proteus comprobarán que las cadenas salen por el puerto serie. Como pueden ver es un ejemplo sencillo pero que muestra el funcionamiento del RTOS. Al ejecutarlo pueden comprobar que primero se ejecuta la Tarea 1, pero después comprobarán que las tareas no se ejecutan en orden secuencial porque la Tarea 2 se ejecutará cada 2 segundos y la Tarea 3 cada 3 segundos.
La no ejecución secuencial de cada tarea se debe al parámetro rate de la directiva #task, que le dice al planificador con que frecuencia ejecutar cada tarea. Este programa puede ser fácilmente modificado para cualquier aplicación específica, un ejemplo que se me ocurre es la lectura de teclados y eliminación de rebotes.
Como tarea les dejo que elaboren un programa sin el uso del RTOS que haga lo mismo que este.
#include <18F258.h>
#fuses HS, NOWDT, NOPROTECT, NOLVP, NODEBUG, NOBROWNOUT
#use delay (clock = 20 000 000)
#use rs232(baud = 9600, uart1)
#include <osa.h>
void Init (void);
void Tarea1 (void);
void Tarea2 (void);
void Tarea3 (void);
void main (void)
{
Init(); // Init periphery
OS_Init(); // Init OS
OS_Task_Define(Tarea1); // Define tasks.
OS_Task_Define(Tarea2);
OS_Task_Define(Tarea3);
OS_Task_Create(0, Tarea1); // Create tasks.
OS_Task_Create(0, Tarea2);
OS_Task_Create(0, Tarea3);
OS_EI(); // Enable interrupts
OS_Run(); // Running scheduler
}
void Init (void)
{
// TImer2 used for system ticks
// post = 4, period = 250*4*5* 0.2 us = 1 ms
setup_timer_2(T2_DIV_BY_4, (250-1) , 5);
enable_interrupts(GLOBAL);
enable_interrupts(INT_TIMER2);
}
// System timer (for system ticks)
#INT_TIMER2
void timer2_isr (void)
{
OS_Timer();
}
void Tarea1(void)
{
for (;;)
{
printf("Ejecutada tarea 1\r");
OS_Delay(1000);
}
}
void Tarea2 (void)
{
for (;;)
{
printf("Ejecutada tarea 2\r");
OS_Delay(2000);
}
}
void Tarea3 (void)
{
for (;;)
{
printf("Ejecutada tarea 3\r");
OS_Delay(3000);
}
}
#ifndef _OSACFG_H
#define _OSACFG_H
#define OS_TASKS 3
#define OS_DISABLE_PRIORITY
#define OS_ENABLE_TTIMERS
#endif